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: 308144 $")
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 #include "asterisk/aoc.h"
00098 #include "asterisk/callerid.h"
00099 #include "asterisk/cel.h"
00100 #include "asterisk/data.h"
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 enum {
00677 QUEUE_STRATEGY_RINGALL = 0,
00678 QUEUE_STRATEGY_LEASTRECENT,
00679 QUEUE_STRATEGY_FEWESTCALLS,
00680 QUEUE_STRATEGY_RANDOM,
00681 QUEUE_STRATEGY_RRMEMORY,
00682 QUEUE_STRATEGY_LINEAR,
00683 QUEUE_STRATEGY_WRANDOM
00684 };
00685
00686 enum {
00687 QUEUE_AUTOPAUSE_OFF = 0,
00688 QUEUE_AUTOPAUSE_ON,
00689 QUEUE_AUTOPAUSE_ALL
00690 };
00691
00692 enum queue_reload_mask {
00693 QUEUE_RELOAD_PARAMETERS = (1 << 0),
00694 QUEUE_RELOAD_MEMBER = (1 << 1),
00695 QUEUE_RELOAD_RULES = (1 << 2),
00696 QUEUE_RESET_STATS = (1 << 3),
00697 };
00698
00699 static const struct strategy {
00700 int strategy;
00701 const char *name;
00702 } strategies[] = {
00703 { QUEUE_STRATEGY_RINGALL, "ringall" },
00704 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
00705 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
00706 { QUEUE_STRATEGY_RANDOM, "random" },
00707 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
00708 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
00709 { QUEUE_STRATEGY_LINEAR, "linear" },
00710 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
00711 };
00712
00713 static const struct autopause {
00714 int autopause;
00715 const char *name;
00716 } autopausesmodes [] = {
00717 { QUEUE_AUTOPAUSE_OFF,"no" },
00718 { QUEUE_AUTOPAUSE_ON, "yes" },
00719 { QUEUE_AUTOPAUSE_ALL,"all" },
00720 };
00721
00722
00723 static struct ast_taskprocessor *devicestate_tps;
00724
00725 #define DEFAULT_RETRY 5
00726 #define DEFAULT_TIMEOUT 15
00727 #define RECHECK 1
00728 #define MAX_PERIODIC_ANNOUNCEMENTS 10
00729 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
00730
00731 #define MAX_QUEUE_BUCKETS 53
00732
00733 #define RES_OKAY 0
00734 #define RES_EXISTS (-1)
00735 #define RES_OUTOFMEMORY (-2)
00736 #define RES_NOSUCHQUEUE (-3)
00737 #define RES_NOT_DYNAMIC (-4)
00738
00739 static char *app = "Queue";
00740
00741 static char *app_aqm = "AddQueueMember" ;
00742
00743 static char *app_rqm = "RemoveQueueMember" ;
00744
00745 static char *app_pqm = "PauseQueueMember" ;
00746
00747 static char *app_upqm = "UnpauseQueueMember" ;
00748
00749 static char *app_ql = "QueueLog" ;
00750
00751
00752 static const char * const pm_family = "Queue/PersistentMembers";
00753
00754 #define PM_MAX_LEN 8192
00755
00756
00757 static int queue_persistent_members = 0;
00758
00759
00760 static int use_weight = 0;
00761
00762
00763 static int autofill_default = 1;
00764
00765
00766 static int montype_default = 0;
00767
00768
00769 static int shared_lastcall = 1;
00770
00771
00772 static struct ast_event_sub *device_state_sub;
00773
00774
00775 static int update_cdr = 0;
00776
00777 enum queue_result {
00778 QUEUE_UNKNOWN = 0,
00779 QUEUE_TIMEOUT = 1,
00780 QUEUE_JOINEMPTY = 2,
00781 QUEUE_LEAVEEMPTY = 3,
00782 QUEUE_JOINUNAVAIL = 4,
00783 QUEUE_LEAVEUNAVAIL = 5,
00784 QUEUE_FULL = 6,
00785 QUEUE_CONTINUE = 7,
00786 };
00787
00788 static const struct {
00789 enum queue_result id;
00790 char *text;
00791 } queue_results[] = {
00792 { QUEUE_UNKNOWN, "UNKNOWN" },
00793 { QUEUE_TIMEOUT, "TIMEOUT" },
00794 { QUEUE_JOINEMPTY,"JOINEMPTY" },
00795 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
00796 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
00797 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
00798 { QUEUE_FULL, "FULL" },
00799 { QUEUE_CONTINUE, "CONTINUE" },
00800 };
00801
00802 enum queue_timeout_priority {
00803 TIMEOUT_PRIORITY_APP,
00804 TIMEOUT_PRIORITY_CONF,
00805 };
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 struct callattempt {
00820 struct callattempt *q_next;
00821 struct callattempt *call_next;
00822 struct ast_channel *chan;
00823 char interface[256];
00824 int stillgoing;
00825 int metric;
00826 time_t lastcall;
00827 struct call_queue *lastqueue;
00828 struct member *member;
00829
00830 struct ast_party_connected_line connected;
00831
00832 unsigned int pending_connected_update:1;
00833
00834 unsigned int dial_callerid_absent:1;
00835 struct ast_aoc_decoded *aoc_s_rate_list;
00836 };
00837
00838
00839 struct queue_ent {
00840 struct call_queue *parent;
00841 char moh[80];
00842 char announce[80];
00843 char context[AST_MAX_CONTEXT];
00844 char digits[AST_MAX_EXTENSION];
00845 int valid_digits;
00846 int pos;
00847 int prio;
00848 int last_pos_said;
00849 int ring_when_ringing;
00850 time_t last_periodic_announce_time;
00851 int last_periodic_announce_sound;
00852 time_t last_pos;
00853 int opos;
00854 int handled;
00855 int pending;
00856 int max_penalty;
00857 int min_penalty;
00858 int linpos;
00859 int linwrapped;
00860 time_t start;
00861 time_t expire;
00862 int cancel_answered_elsewhere;
00863 struct ast_channel *chan;
00864 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules;
00865 struct penalty_rule *pr;
00866 struct queue_ent *next;
00867 };
00868
00869 struct member {
00870 char interface[80];
00871 char state_exten[AST_MAX_EXTENSION];
00872 char state_context[AST_MAX_CONTEXT];
00873 char state_interface[80];
00874 char membername[80];
00875 int penalty;
00876 int calls;
00877 int dynamic;
00878 int realtime;
00879 int status;
00880 int paused;
00881 time_t lastcall;
00882 struct call_queue *lastqueue;
00883 unsigned int dead:1;
00884 unsigned int delme:1;
00885 char rt_uniqueid[80];
00886 };
00887
00888 enum empty_conditions {
00889 QUEUE_EMPTY_PENALTY = (1 << 0),
00890 QUEUE_EMPTY_PAUSED = (1 << 1),
00891 QUEUE_EMPTY_INUSE = (1 << 2),
00892 QUEUE_EMPTY_RINGING = (1 << 3),
00893 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
00894 QUEUE_EMPTY_INVALID = (1 << 5),
00895 QUEUE_EMPTY_UNKNOWN = (1 << 6),
00896 QUEUE_EMPTY_WRAPUP = (1 << 7),
00897 };
00898
00899
00900 #define ANNOUNCEHOLDTIME_ALWAYS 1
00901 #define ANNOUNCEHOLDTIME_ONCE 2
00902 #define QUEUE_EVENT_VARIABLES 3
00903
00904 struct penalty_rule {
00905 int time;
00906 int max_value;
00907 int min_value;
00908 int max_relative;
00909 int min_relative;
00910 AST_LIST_ENTRY(penalty_rule) list;
00911 };
00912
00913 #define ANNOUNCEPOSITION_YES 1
00914 #define ANNOUNCEPOSITION_NO 2
00915 #define ANNOUNCEPOSITION_MORE_THAN 3
00916 #define ANNOUNCEPOSITION_LIMIT 4
00917
00918 struct call_queue {
00919 AST_DECLARE_STRING_FIELDS(
00920
00921 AST_STRING_FIELD(name);
00922
00923 AST_STRING_FIELD(moh);
00924
00925 AST_STRING_FIELD(announce);
00926
00927 AST_STRING_FIELD(context);
00928
00929 AST_STRING_FIELD(membermacro);
00930
00931 AST_STRING_FIELD(membergosub);
00932
00933 AST_STRING_FIELD(defaultrule);
00934
00935 AST_STRING_FIELD(sound_next);
00936
00937 AST_STRING_FIELD(sound_thereare);
00938
00939 AST_STRING_FIELD(sound_calls);
00940
00941 AST_STRING_FIELD(queue_quantity1);
00942
00943 AST_STRING_FIELD(queue_quantity2);
00944
00945 AST_STRING_FIELD(sound_holdtime);
00946
00947 AST_STRING_FIELD(sound_minutes);
00948
00949 AST_STRING_FIELD(sound_minute);
00950
00951 AST_STRING_FIELD(sound_seconds);
00952
00953 AST_STRING_FIELD(sound_thanks);
00954
00955 AST_STRING_FIELD(sound_callerannounce);
00956
00957 AST_STRING_FIELD(sound_reporthold);
00958 );
00959
00960 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
00961 unsigned int dead:1;
00962 unsigned int eventwhencalled:2;
00963 unsigned int ringinuse:1;
00964 unsigned int setinterfacevar:1;
00965 unsigned int setqueuevar:1;
00966 unsigned int setqueueentryvar:1;
00967 unsigned int reportholdtime:1;
00968 unsigned int wrapped:1;
00969 unsigned int timeoutrestart:1;
00970 unsigned int announceholdtime:2;
00971 unsigned int announceposition:3;
00972 int strategy:4;
00973 unsigned int maskmemberstatus:1;
00974 unsigned int realtime:1;
00975 unsigned int found:1;
00976 unsigned int relativeperiodicannounce:1;
00977 enum empty_conditions joinempty;
00978 enum empty_conditions leavewhenempty;
00979 int announcepositionlimit;
00980 int announcefrequency;
00981 int minannouncefrequency;
00982 int periodicannouncefrequency;
00983 int numperiodicannounce;
00984 int randomperiodicannounce;
00985 int roundingseconds;
00986 int holdtime;
00987 int talktime;
00988 int callscompleted;
00989 int callsabandoned;
00990 int servicelevel;
00991 int callscompletedinsl;
00992 char monfmt[8];
00993 int montype;
00994 int count;
00995 int maxlen;
00996 int wrapuptime;
00997 int penaltymemberslimit;
00998
00999 int retry;
01000 int timeout;
01001 int weight;
01002 int autopause;
01003 int timeoutpriority;
01004
01005
01006 int rrpos;
01007 int memberdelay;
01008 int autofill;
01009
01010 struct ao2_container *members;
01011
01012
01013
01014
01015
01016 int membercount;
01017 struct queue_ent *head;
01018 AST_LIST_ENTRY(call_queue) list;
01019 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules;
01020 };
01021
01022 struct rule_list {
01023 char name[80];
01024 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
01025 AST_LIST_ENTRY(rule_list) list;
01026 };
01027
01028 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
01029
01030 static struct ao2_container *queues;
01031
01032 static void update_realtime_members(struct call_queue *q);
01033 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
01034
01035 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
01036
01037 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
01038 {
01039 int i;
01040
01041 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
01042 if (queue_results[i].id == res) {
01043 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
01044 return;
01045 }
01046 }
01047 }
01048
01049 static const char *int2strat(int strategy)
01050 {
01051 int x;
01052
01053 for (x = 0; x < ARRAY_LEN(strategies); x++) {
01054 if (strategy == strategies[x].strategy)
01055 return strategies[x].name;
01056 }
01057
01058 return "<unknown>";
01059 }
01060
01061 static int strat2int(const char *strategy)
01062 {
01063 int x;
01064
01065 for (x = 0; x < ARRAY_LEN(strategies); x++) {
01066 if (!strcasecmp(strategy, strategies[x].name))
01067 return strategies[x].strategy;
01068 }
01069
01070 return -1;
01071 }
01072
01073 static int autopause2int(const char *autopause)
01074 {
01075 int x;
01076
01077 if (ast_strlen_zero(autopause))
01078 return QUEUE_AUTOPAUSE_OFF;
01079
01080
01081 if(ast_true(autopause))
01082 return QUEUE_AUTOPAUSE_ON;
01083
01084 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
01085 if (!strcasecmp(autopause, autopausesmodes[x].name))
01086 return autopausesmodes[x].autopause;
01087 }
01088
01089
01090 return QUEUE_AUTOPAUSE_OFF;
01091 }
01092
01093 static int queue_hash_cb(const void *obj, const int flags)
01094 {
01095 const struct call_queue *q = obj;
01096
01097 return ast_str_case_hash(q->name);
01098 }
01099
01100 static int queue_cmp_cb(void *obj, void *arg, int flags)
01101 {
01102 struct call_queue *q = obj, *q2 = arg;
01103 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
01104 }
01105
01106 #ifdef REF_DEBUG_ONLY_QUEUES
01107 #define queue_ref(a) __ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
01108 #define queue_unref(a) __ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
01109 #define queue_t_ref(a,b) __ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01110 #define queue_t_unref(a,b) __ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01111 #define queues_t_link(c,q,tag) __ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01112 #define queues_t_unlink(c,q,tag) __ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01113 #else
01114 #define queue_t_ref(a,b) queue_ref(a)
01115 #define queue_t_unref(a,b) queue_unref(a)
01116 #define queues_t_link(c,q,tag) ao2_t_link(c,q,tag)
01117 #define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag)
01118 static inline struct call_queue *queue_ref(struct call_queue *q)
01119 {
01120 ao2_ref(q, 1);
01121 return q;
01122 }
01123
01124 static inline struct call_queue *queue_unref(struct call_queue *q)
01125 {
01126 ao2_ref(q, -1);
01127 return q;
01128 }
01129 #endif
01130
01131
01132 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
01133 {
01134 char interfacevar[256]="";
01135 float sl = 0;
01136
01137 ao2_lock(q);
01138
01139 if (q->setqueuevar) {
01140 sl = 0;
01141 if (q->callscompleted > 0)
01142 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
01143
01144 snprintf(interfacevar, sizeof(interfacevar),
01145 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
01146 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
01147
01148 ao2_unlock(q);
01149
01150 pbx_builtin_setvar_multiple(chan, interfacevar);
01151 } else {
01152 ao2_unlock(q);
01153 }
01154 }
01155
01156
01157 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
01158 {
01159 struct queue_ent *cur;
01160
01161 if (!q || !new)
01162 return;
01163 if (prev) {
01164 cur = prev->next;
01165 prev->next = new;
01166 } else {
01167 cur = q->head;
01168 q->head = new;
01169 }
01170 new->next = cur;
01171
01172
01173
01174
01175 queue_ref(q);
01176 new->parent = q;
01177 new->pos = ++(*pos);
01178 new->opos = *pos;
01179 }
01180
01181
01182
01183
01184
01185
01186
01187 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
01188 {
01189 struct member *member;
01190 struct ao2_iterator mem_iter;
01191
01192 ao2_lock(q);
01193 mem_iter = ao2_iterator_init(q->members, 0);
01194 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
01195 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
01196 if (conditions & QUEUE_EMPTY_PENALTY) {
01197 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
01198 continue;
01199 }
01200 }
01201
01202 switch (member->status) {
01203 case AST_DEVICE_INVALID:
01204 if (conditions & QUEUE_EMPTY_INVALID) {
01205 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
01206 break;
01207 }
01208 goto default_case;
01209 case AST_DEVICE_UNAVAILABLE:
01210 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
01211 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
01212 break;
01213 }
01214 goto default_case;
01215 case AST_DEVICE_INUSE:
01216 if (conditions & QUEUE_EMPTY_INUSE) {
01217 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
01218 break;
01219 }
01220 goto default_case;
01221 case AST_DEVICE_RINGING:
01222 if (conditions & QUEUE_EMPTY_RINGING) {
01223 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
01224 break;
01225 }
01226 case AST_DEVICE_UNKNOWN:
01227 if (conditions & QUEUE_EMPTY_UNKNOWN) {
01228 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
01229 break;
01230 }
01231
01232 default:
01233 default_case:
01234 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
01235 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
01236 break;
01237 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
01238 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
01239 break;
01240 } else {
01241 ao2_unlock(q);
01242 ao2_ref(member, -1);
01243 ao2_iterator_destroy(&mem_iter);
01244 ast_debug(4, "%s is available.\n", member->membername);
01245 return 0;
01246 }
01247 break;
01248 }
01249 }
01250 ao2_iterator_destroy(&mem_iter);
01251
01252 ao2_unlock(q);
01253 return -1;
01254 }
01255
01256 struct statechange {
01257 AST_LIST_ENTRY(statechange) entry;
01258 int state;
01259 char dev[0];
01260 };
01261
01262
01263
01264
01265
01266
01267 static int update_status(struct call_queue *q, struct member *m, const int status)
01268 {
01269 m->status = status;
01270
01271 if (q->maskmemberstatus)
01272 return 0;
01273
01274 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01275 "Queue: %s\r\n"
01276 "Location: %s\r\n"
01277 "MemberName: %s\r\n"
01278 "Membership: %s\r\n"
01279 "Penalty: %d\r\n"
01280 "CallsTaken: %d\r\n"
01281 "LastCall: %d\r\n"
01282 "Status: %d\r\n"
01283 "Paused: %d\r\n",
01284 q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
01285 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
01286 );
01287
01288 return 0;
01289 }
01290
01291
01292 static int handle_statechange(void *datap)
01293 {
01294 struct statechange *sc = datap;
01295 struct ao2_iterator miter, qiter;
01296 struct member *m;
01297 struct call_queue *q;
01298 char interface[80], *slash_pos;
01299 int found = 0;
01300
01301 qiter = ao2_iterator_init(queues, 0);
01302 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
01303 ao2_lock(q);
01304
01305 miter = ao2_iterator_init(q->members, 0);
01306 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01307 ast_copy_string(interface, m->state_interface, sizeof(interface));
01308
01309 if ((slash_pos = strchr(interface, '/')))
01310 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
01311 *slash_pos = '\0';
01312
01313 if (!strcasecmp(interface, sc->dev)) {
01314 found = 1;
01315 update_status(q, m, sc->state);
01316 ao2_ref(m, -1);
01317 break;
01318 }
01319 }
01320 ao2_iterator_destroy(&miter);
01321
01322 ao2_unlock(q);
01323 queue_t_unref(q, "Done with iterator");
01324 }
01325 ao2_iterator_destroy(&qiter);
01326
01327 if (found)
01328 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01329 else
01330 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, ast_devstate2str(sc->state));
01331
01332 ast_free(sc);
01333 return 0;
01334 }
01335
01336 static void device_state_cb(const struct ast_event *event, void *unused)
01337 {
01338 enum ast_device_state state;
01339 const char *device;
01340 struct statechange *sc;
01341 size_t datapsize;
01342
01343 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01344 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
01345
01346 if (ast_strlen_zero(device)) {
01347 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
01348 return;
01349 }
01350 datapsize = sizeof(*sc) + strlen(device) + 1;
01351 if (!(sc = ast_calloc(1, datapsize))) {
01352 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
01353 return;
01354 }
01355 sc->state = state;
01356 strcpy(sc->dev, device);
01357 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
01358 ast_free(sc);
01359 }
01360 }
01361
01362
01363 static int extensionstate2devicestate(int state)
01364 {
01365 switch (state) {
01366 case AST_EXTENSION_NOT_INUSE:
01367 state = AST_DEVICE_NOT_INUSE;
01368 break;
01369 case AST_EXTENSION_INUSE:
01370 state = AST_DEVICE_INUSE;
01371 break;
01372 case AST_EXTENSION_BUSY:
01373 state = AST_DEVICE_BUSY;
01374 break;
01375 case AST_EXTENSION_RINGING:
01376 state = AST_DEVICE_RINGING;
01377 break;
01378 case AST_EXTENSION_ONHOLD:
01379 state = AST_DEVICE_ONHOLD;
01380 break;
01381 case AST_EXTENSION_UNAVAILABLE:
01382 state = AST_DEVICE_UNAVAILABLE;
01383 break;
01384 case AST_EXTENSION_REMOVED:
01385 case AST_EXTENSION_DEACTIVATED:
01386 default:
01387 state = AST_DEVICE_INVALID;
01388 break;
01389 }
01390
01391 return state;
01392 }
01393
01394 static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
01395 {
01396 struct ao2_iterator miter, qiter;
01397 struct member *m;
01398 struct call_queue *q;
01399 int found = 0, device_state = extensionstate2devicestate(state);
01400
01401 qiter = ao2_iterator_init(queues, 0);
01402 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
01403 ao2_lock(q);
01404
01405 miter = ao2_iterator_init(q->members, 0);
01406 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01407 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
01408 update_status(q, m, device_state);
01409 ao2_ref(m, -1);
01410 found = 1;
01411 break;
01412 }
01413 }
01414 ao2_iterator_destroy(&miter);
01415
01416 ao2_unlock(q);
01417 queue_t_unref(q, "Done with iterator");
01418 }
01419 ao2_iterator_destroy(&qiter);
01420
01421 if (found) {
01422 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
01423 } else {
01424 ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
01425 exten, context, device_state, ast_devstate2str(device_state));
01426 }
01427
01428 return 0;
01429 }
01430
01431
01432 static int get_queue_member_status(struct member *cur)
01433 {
01434 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
01435 }
01436
01437
01438 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
01439 {
01440 struct member *cur;
01441
01442 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
01443 cur->penalty = penalty;
01444 cur->paused = paused;
01445 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
01446 if (!ast_strlen_zero(state_interface))
01447 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
01448 else
01449 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
01450 if (!ast_strlen_zero(membername))
01451 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
01452 else
01453 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
01454 if (!strchr(cur->interface, '/'))
01455 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
01456 if (!strncmp(cur->state_interface, "hint:", 5)) {
01457 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
01458 char *exten = strsep(&context, "@") + 5;
01459
01460 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
01461 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
01462 }
01463 cur->status = get_queue_member_status(cur);
01464 }
01465
01466 return cur;
01467 }
01468
01469
01470 static int compress_char(const char c)
01471 {
01472 if (c < 32)
01473 return 0;
01474 else if (c > 96)
01475 return c - 64;
01476 else
01477 return c - 32;
01478 }
01479
01480 static int member_hash_fn(const void *obj, const int flags)
01481 {
01482 const struct member *mem = obj;
01483 const char *chname = strchr(mem->interface, '/');
01484 int ret = 0, i;
01485 if (!chname)
01486 chname = mem->interface;
01487 for (i = 0; i < 5 && chname[i]; i++)
01488 ret += compress_char(chname[i]) << (i * 6);
01489 return ret;
01490 }
01491
01492 static int member_cmp_fn(void *obj1, void *obj2, int flags)
01493 {
01494 struct member *mem1 = obj1, *mem2 = obj2;
01495 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
01496 }
01497
01498
01499
01500
01501
01502 static void init_queue(struct call_queue *q)
01503 {
01504 int i;
01505 struct penalty_rule *pr_iter;
01506
01507 q->dead = 0;
01508 q->retry = DEFAULT_RETRY;
01509 q->timeout = DEFAULT_TIMEOUT;
01510 q->maxlen = 0;
01511 q->announcefrequency = 0;
01512 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
01513 q->announceholdtime = 1;
01514 q->announcepositionlimit = 10;
01515 q->announceposition = ANNOUNCEPOSITION_YES;
01516 q->roundingseconds = 0;
01517 q->servicelevel = 0;
01518 q->ringinuse = 1;
01519 q->setinterfacevar = 0;
01520 q->setqueuevar = 0;
01521 q->setqueueentryvar = 0;
01522 q->autofill = autofill_default;
01523 q->montype = montype_default;
01524 q->monfmt[0] = '\0';
01525 q->reportholdtime = 0;
01526 q->wrapuptime = 0;
01527 q->penaltymemberslimit = 0;
01528 q->joinempty = 0;
01529 q->leavewhenempty = 0;
01530 q->memberdelay = 0;
01531 q->maskmemberstatus = 0;
01532 q->eventwhencalled = 0;
01533 q->weight = 0;
01534 q->timeoutrestart = 0;
01535 q->periodicannouncefrequency = 0;
01536 q->randomperiodicannounce = 0;
01537 q->numperiodicannounce = 0;
01538 q->autopause = QUEUE_AUTOPAUSE_OFF;
01539 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
01540 if (!q->members) {
01541 if (q->strategy == QUEUE_STRATEGY_LINEAR)
01542
01543 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
01544 else
01545 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
01546 }
01547 q->found = 1;
01548
01549 ast_string_field_set(q, sound_next, "queue-youarenext");
01550 ast_string_field_set(q, sound_thereare, "queue-thereare");
01551 ast_string_field_set(q, sound_calls, "queue-callswaiting");
01552 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
01553 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
01554 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
01555 ast_string_field_set(q, sound_minutes, "queue-minutes");
01556 ast_string_field_set(q, sound_minute, "queue-minute");
01557 ast_string_field_set(q, sound_seconds, "queue-seconds");
01558 ast_string_field_set(q, sound_thanks, "queue-thankyou");
01559 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
01560
01561 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
01562 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
01563
01564 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
01565 if (q->sound_periodicannounce[i])
01566 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
01567 }
01568
01569 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
01570 ast_free(pr_iter);
01571 }
01572
01573 static void clear_queue(struct call_queue *q)
01574 {
01575 q->holdtime = 0;
01576 q->callscompleted = 0;
01577 q->callsabandoned = 0;
01578 q->callscompletedinsl = 0;
01579 q->talktime = 0;
01580
01581 if (q->members) {
01582 struct member *mem;
01583 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01584 while ((mem = ao2_iterator_next(&mem_iter))) {
01585 mem->calls = 0;
01586 mem->lastcall = 0;
01587 ao2_ref(mem, -1);
01588 }
01589 ao2_iterator_destroy(&mem_iter);
01590 }
01591 }
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602 static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
01603 {
01604 char *timestr, *maxstr, *minstr, *contentdup;
01605 struct penalty_rule *rule = NULL, *rule_iter;
01606 struct rule_list *rl_iter;
01607 int penaltychangetime, inserted = 0;
01608
01609 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
01610 return -1;
01611 }
01612
01613 contentdup = ast_strdupa(content);
01614
01615 if (!(maxstr = strchr(contentdup, ','))) {
01616 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
01617 ast_free(rule);
01618 return -1;
01619 }
01620
01621 *maxstr++ = '\0';
01622 timestr = contentdup;
01623
01624 if ((penaltychangetime = atoi(timestr)) < 0) {
01625 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
01626 ast_free(rule);
01627 return -1;
01628 }
01629
01630 rule->time = penaltychangetime;
01631
01632 if ((minstr = strchr(maxstr,',')))
01633 *minstr++ = '\0';
01634
01635
01636
01637 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
01638 rule->max_relative = 1;
01639 }
01640
01641 rule->max_value = atoi(maxstr);
01642
01643 if (!ast_strlen_zero(minstr)) {
01644 if (*minstr == '+' || *minstr == '-')
01645 rule->min_relative = 1;
01646 rule->min_value = atoi(minstr);
01647 } else
01648 rule->min_relative = 1;
01649
01650
01651 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
01652 if (strcasecmp(rl_iter->name, list_name))
01653 continue;
01654
01655 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
01656 if (rule->time < rule_iter->time) {
01657 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
01658 inserted = 1;
01659 break;
01660 }
01661 }
01662 AST_LIST_TRAVERSE_SAFE_END;
01663
01664 if (!inserted) {
01665 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
01666 }
01667 }
01668
01669 return 0;
01670 }
01671
01672 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
01673 {
01674 char *value_copy = ast_strdupa(value);
01675 char *option = NULL;
01676 while ((option = strsep(&value_copy, ","))) {
01677 if (!strcasecmp(option, "paused")) {
01678 *empty |= QUEUE_EMPTY_PAUSED;
01679 } else if (!strcasecmp(option, "penalty")) {
01680 *empty |= QUEUE_EMPTY_PENALTY;
01681 } else if (!strcasecmp(option, "inuse")) {
01682 *empty |= QUEUE_EMPTY_INUSE;
01683 } else if (!strcasecmp(option, "ringing")) {
01684 *empty |= QUEUE_EMPTY_RINGING;
01685 } else if (!strcasecmp(option, "invalid")) {
01686 *empty |= QUEUE_EMPTY_INVALID;
01687 } else if (!strcasecmp(option, "wrapup")) {
01688 *empty |= QUEUE_EMPTY_WRAPUP;
01689 } else if (!strcasecmp(option, "unavailable")) {
01690 *empty |= QUEUE_EMPTY_UNAVAILABLE;
01691 } else if (!strcasecmp(option, "unknown")) {
01692 *empty |= QUEUE_EMPTY_UNKNOWN;
01693 } else if (!strcasecmp(option, "loose")) {
01694 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
01695 } else if (!strcasecmp(option, "strict")) {
01696 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
01697 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
01698 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
01699 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
01700 *empty = 0;
01701 } else {
01702 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
01703 }
01704 }
01705 }
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
01716 {
01717 if (!strcasecmp(param, "musicclass") ||
01718 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
01719 ast_string_field_set(q, moh, val);
01720 } else if (!strcasecmp(param, "announce")) {
01721 ast_string_field_set(q, announce, val);
01722 } else if (!strcasecmp(param, "context")) {
01723 ast_string_field_set(q, context, val);
01724 } else if (!strcasecmp(param, "timeout")) {
01725 q->timeout = atoi(val);
01726 if (q->timeout < 0)
01727 q->timeout = DEFAULT_TIMEOUT;
01728 } else if (!strcasecmp(param, "ringinuse")) {
01729 q->ringinuse = ast_true(val);
01730 } else if (!strcasecmp(param, "setinterfacevar")) {
01731 q->setinterfacevar = ast_true(val);
01732 } else if (!strcasecmp(param, "setqueuevar")) {
01733 q->setqueuevar = ast_true(val);
01734 } else if (!strcasecmp(param, "setqueueentryvar")) {
01735 q->setqueueentryvar = ast_true(val);
01736 } else if (!strcasecmp(param, "monitor-format")) {
01737 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01738 } else if (!strcasecmp(param, "membermacro")) {
01739 ast_string_field_set(q, membermacro, val);
01740 } else if (!strcasecmp(param, "membergosub")) {
01741 ast_string_field_set(q, membergosub, val);
01742 } else if (!strcasecmp(param, "queue-youarenext")) {
01743 ast_string_field_set(q, sound_next, val);
01744 } else if (!strcasecmp(param, "queue-thereare")) {
01745 ast_string_field_set(q, sound_thereare, val);
01746 } else if (!strcasecmp(param, "queue-callswaiting")) {
01747 ast_string_field_set(q, sound_calls, val);
01748 } else if (!strcasecmp(param, "queue-quantity1")) {
01749 ast_string_field_set(q, queue_quantity1, val);
01750 } else if (!strcasecmp(param, "queue-quantity2")) {
01751 ast_string_field_set(q, queue_quantity2, val);
01752 } else if (!strcasecmp(param, "queue-holdtime")) {
01753 ast_string_field_set(q, sound_holdtime, val);
01754 } else if (!strcasecmp(param, "queue-minutes")) {
01755 ast_string_field_set(q, sound_minutes, val);
01756 } else if (!strcasecmp(param, "queue-minute")) {
01757 ast_string_field_set(q, sound_minute, val);
01758 } else if (!strcasecmp(param, "queue-seconds")) {
01759 ast_string_field_set(q, sound_seconds, val);
01760 } else if (!strcasecmp(param, "queue-thankyou")) {
01761 ast_string_field_set(q, sound_thanks, val);
01762 } else if (!strcasecmp(param, "queue-callerannounce")) {
01763 ast_string_field_set(q, sound_callerannounce, val);
01764 } else if (!strcasecmp(param, "queue-reporthold")) {
01765 ast_string_field_set(q, sound_reporthold, val);
01766 } else if (!strcasecmp(param, "announce-frequency")) {
01767 q->announcefrequency = atoi(val);
01768 } else if (!strcasecmp(param, "min-announce-frequency")) {
01769 q->minannouncefrequency = atoi(val);
01770 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
01771 } else if (!strcasecmp(param, "announce-round-seconds")) {
01772 q->roundingseconds = atoi(val);
01773
01774 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
01775 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
01776 if (linenum >= 0) {
01777 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01778 "using 0 instead for queue '%s' at line %d of queues.conf\n",
01779 val, param, q->name, linenum);
01780 } else {
01781 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01782 "using 0 instead for queue '%s'\n", val, param, q->name);
01783 }
01784 q->roundingseconds=0;
01785 }
01786 } else if (!strcasecmp(param, "announce-holdtime")) {
01787 if (!strcasecmp(val, "once"))
01788 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01789 else if (ast_true(val))
01790 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01791 else
01792 q->announceholdtime = 0;
01793 } else if (!strcasecmp(param, "announce-position")) {
01794 if (!strcasecmp(val, "limit"))
01795 q->announceposition = ANNOUNCEPOSITION_LIMIT;
01796 else if (!strcasecmp(val, "more"))
01797 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
01798 else if (ast_true(val))
01799 q->announceposition = ANNOUNCEPOSITION_YES;
01800 else
01801 q->announceposition = ANNOUNCEPOSITION_NO;
01802 } else if (!strcasecmp(param, "announce-position-limit")) {
01803 q->announcepositionlimit = atoi(val);
01804 } else if (!strcasecmp(param, "periodic-announce")) {
01805 if (strchr(val, ',')) {
01806 char *s, *buf = ast_strdupa(val);
01807 unsigned int i = 0;
01808
01809 while ((s = strsep(&buf, ",|"))) {
01810 if (!q->sound_periodicannounce[i])
01811 q->sound_periodicannounce[i] = ast_str_create(16);
01812 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
01813 i++;
01814 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01815 break;
01816 }
01817 q->numperiodicannounce = i;
01818 } else {
01819 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
01820 q->numperiodicannounce = 1;
01821 }
01822 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01823 q->periodicannouncefrequency = atoi(val);
01824 } else if (!strcasecmp(param, "relative-periodic-announce")) {
01825 q->relativeperiodicannounce = ast_true(val);
01826 } else if (!strcasecmp(param, "random-periodic-announce")) {
01827 q->randomperiodicannounce = ast_true(val);
01828 } else if (!strcasecmp(param, "retry")) {
01829 q->retry = atoi(val);
01830 if (q->retry <= 0)
01831 q->retry = DEFAULT_RETRY;
01832 } else if (!strcasecmp(param, "wrapuptime")) {
01833 q->wrapuptime = atoi(val);
01834 } else if (!strcasecmp(param, "penaltymemberslimit")) {
01835 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
01836 q->penaltymemberslimit = 0;
01837 }
01838 } else if (!strcasecmp(param, "autofill")) {
01839 q->autofill = ast_true(val);
01840 } else if (!strcasecmp(param, "monitor-type")) {
01841 if (!strcasecmp(val, "mixmonitor"))
01842 q->montype = 1;
01843 } else if (!strcasecmp(param, "autopause")) {
01844 q->autopause = autopause2int(val);
01845 } else if (!strcasecmp(param, "maxlen")) {
01846 q->maxlen = atoi(val);
01847 if (q->maxlen < 0)
01848 q->maxlen = 0;
01849 } else if (!strcasecmp(param, "servicelevel")) {
01850 q->servicelevel= atoi(val);
01851 } else if (!strcasecmp(param, "strategy")) {
01852 int strategy;
01853
01854
01855 if (failunknown) {
01856 return;
01857 }
01858 strategy = strat2int(val);
01859 if (strategy < 0) {
01860 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01861 val, q->name);
01862 q->strategy = QUEUE_STRATEGY_RINGALL;
01863 }
01864 if (strategy == q->strategy) {
01865 return;
01866 }
01867 if (strategy == QUEUE_STRATEGY_LINEAR) {
01868 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
01869 return;
01870 }
01871 q->strategy = strategy;
01872 } else if (!strcasecmp(param, "joinempty")) {
01873 parse_empty_options(val, &q->joinempty, 1);
01874 } else if (!strcasecmp(param, "leavewhenempty")) {
01875 parse_empty_options(val, &q->leavewhenempty, 0);
01876 } else if (!strcasecmp(param, "eventmemberstatus")) {
01877 q->maskmemberstatus = !ast_true(val);
01878 } else if (!strcasecmp(param, "eventwhencalled")) {
01879 if (!strcasecmp(val, "vars")) {
01880 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
01881 } else {
01882 q->eventwhencalled = ast_true(val) ? 1 : 0;
01883 }
01884 } else if (!strcasecmp(param, "reportholdtime")) {
01885 q->reportholdtime = ast_true(val);
01886 } else if (!strcasecmp(param, "memberdelay")) {
01887 q->memberdelay = atoi(val);
01888 } else if (!strcasecmp(param, "weight")) {
01889 q->weight = atoi(val);
01890 } else if (!strcasecmp(param, "timeoutrestart")) {
01891 q->timeoutrestart = ast_true(val);
01892 } else if (!strcasecmp(param, "defaultrule")) {
01893 ast_string_field_set(q, defaultrule, val);
01894 } else if (!strcasecmp(param, "timeoutpriority")) {
01895 if (!strcasecmp(val, "conf")) {
01896 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
01897 } else {
01898 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
01899 }
01900 } else if (failunknown) {
01901 if (linenum >= 0) {
01902 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
01903 q->name, param, linenum);
01904 } else {
01905 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
01906 }
01907 }
01908 }
01909
01910
01911
01912
01913
01914
01915
01916 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)
01917 {
01918 struct member *m;
01919 struct ao2_iterator mem_iter;
01920 int penalty = 0;
01921 int paused = 0;
01922 int found = 0;
01923
01924 if (ast_strlen_zero(rt_uniqueid)) {
01925 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
01926 return;
01927 }
01928
01929 if (penalty_str) {
01930 penalty = atoi(penalty_str);
01931 if (penalty < 0)
01932 penalty = 0;
01933 }
01934
01935 if (paused_str) {
01936 paused = atoi(paused_str);
01937 if (paused < 0)
01938 paused = 0;
01939 }
01940
01941
01942 mem_iter = ao2_iterator_init(q->members, 0);
01943 while ((m = ao2_iterator_next(&mem_iter))) {
01944 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
01945 m->dead = 0;
01946 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
01947 if (paused_str)
01948 m->paused = paused;
01949 if (strcasecmp(state_interface, m->state_interface)) {
01950 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
01951 }
01952 m->penalty = penalty;
01953 found = 1;
01954 ao2_ref(m, -1);
01955 break;
01956 }
01957 ao2_ref(m, -1);
01958 }
01959 ao2_iterator_destroy(&mem_iter);
01960
01961
01962 if (!found) {
01963 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
01964 m->dead = 0;
01965 m->realtime = 1;
01966 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
01967 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
01968 ao2_link(q->members, m);
01969 ao2_ref(m, -1);
01970 m = NULL;
01971 q->membercount++;
01972 }
01973 }
01974 }
01975
01976
01977 static void free_members(struct call_queue *q, int all)
01978 {
01979
01980 struct member *cur;
01981 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01982
01983 while ((cur = ao2_iterator_next(&mem_iter))) {
01984 if (all || !cur->dynamic) {
01985 ao2_unlink(q->members, cur);
01986 q->membercount--;
01987 }
01988 ao2_ref(cur, -1);
01989 }
01990 ao2_iterator_destroy(&mem_iter);
01991 }
01992
01993
01994 static void destroy_queue(void *obj)
01995 {
01996 struct call_queue *q = obj;
01997 int i;
01998
01999 free_members(q, 1);
02000 ast_string_field_free_memory(q);
02001 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
02002 if (q->sound_periodicannounce[i])
02003 free(q->sound_periodicannounce[i]);
02004 }
02005 ao2_ref(q->members, -1);
02006 }
02007
02008 static struct call_queue *alloc_queue(const char *queuename)
02009 {
02010 struct call_queue *q;
02011
02012 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
02013 if (ast_string_field_init(q, 64)) {
02014 queue_t_unref(q, "String field allocation failed");
02015 return NULL;
02016 }
02017 ast_string_field_set(q, name, queuename);
02018 }
02019 return q;
02020 }
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030
02031
02032 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
02033 {
02034 struct ast_variable *v;
02035 struct call_queue *q, tmpq = {
02036 .name = queuename,
02037 };
02038 struct member *m;
02039 struct ao2_iterator mem_iter;
02040 char *interface = NULL;
02041 const char *tmp_name;
02042 char *tmp;
02043 char tmpbuf[64];
02044
02045
02046 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
02047 ao2_lock(q);
02048 if (!q->realtime) {
02049 if (q->dead) {
02050 ao2_unlock(q);
02051 queue_t_unref(q, "Queue is dead; can't return it");
02052 return NULL;
02053 } else {
02054 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
02055 ao2_unlock(q);
02056 return q;
02057 }
02058 }
02059 } else if (!member_config)
02060
02061 return NULL;
02062
02063
02064 if (!queue_vars) {
02065
02066 if (q) {
02067
02068
02069
02070 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
02071
02072 q->dead = 1;
02073
02074 queues_t_unlink(queues, q, "Unused; removing from container");
02075 ao2_unlock(q);
02076 queue_t_unref(q, "Queue is dead; can't return it");
02077 }
02078 return NULL;
02079 }
02080
02081
02082 if (!q) {
02083 struct ast_variable *tmpvar = NULL;
02084 if (!(q = alloc_queue(queuename)))
02085 return NULL;
02086 ao2_lock(q);
02087 clear_queue(q);
02088 q->realtime = 1;
02089 q->membercount = 0;
02090
02091
02092
02093 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
02094 if (!strcasecmp(tmpvar->name, "strategy")) {
02095 q->strategy = strat2int(tmpvar->value);
02096 if (q->strategy < 0) {
02097 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02098 tmpvar->value, q->name);
02099 q->strategy = QUEUE_STRATEGY_RINGALL;
02100 }
02101 break;
02102 }
02103 }
02104
02105 if (!tmpvar)
02106 q->strategy = QUEUE_STRATEGY_RINGALL;
02107 queues_t_link(queues, q, "Add queue to container");
02108 }
02109 init_queue(q);
02110
02111 memset(tmpbuf, 0, sizeof(tmpbuf));
02112 for (v = queue_vars; v; v = v->next) {
02113
02114 if ((tmp = strchr(v->name, '_'))) {
02115 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
02116 tmp_name = tmpbuf;
02117 tmp = tmpbuf;
02118 while ((tmp = strchr(tmp, '_')))
02119 *tmp++ = '-';
02120 } else
02121 tmp_name = v->name;
02122
02123
02124
02125
02126 queue_set_param(q, tmp_name, v->value, -1, 0);
02127 }
02128
02129
02130
02131 mem_iter = ao2_iterator_init(q->members, 0);
02132 while ((m = ao2_iterator_next(&mem_iter))) {
02133 q->membercount++;
02134 if (m->realtime)
02135 m->dead = 1;
02136 ao2_ref(m, -1);
02137 }
02138 ao2_iterator_destroy(&mem_iter);
02139
02140 while ((interface = ast_category_browse(member_config, interface))) {
02141 rt_handle_member_record(q, interface,
02142 ast_variable_retrieve(member_config, interface, "uniqueid"),
02143 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
02144 ast_variable_retrieve(member_config, interface, "penalty"),
02145 ast_variable_retrieve(member_config, interface, "paused"),
02146 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
02147 }
02148
02149
02150 mem_iter = ao2_iterator_init(q->members, 0);
02151 while ((m = ao2_iterator_next(&mem_iter))) {
02152 if (m->dead) {
02153 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02154 ao2_unlink(q->members, m);
02155 q->membercount--;
02156 }
02157 ao2_ref(m, -1);
02158 }
02159 ao2_iterator_destroy(&mem_iter);
02160
02161 ao2_unlock(q);
02162
02163 return q;
02164 }
02165
02166 static struct call_queue *load_realtime_queue(const char *queuename)
02167 {
02168 struct ast_variable *queue_vars;
02169 struct ast_config *member_config = NULL;
02170 struct call_queue *q = NULL, tmpq = {
02171 .name = queuename,
02172 };
02173 int prev_weight = 0;
02174
02175
02176 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
02177
02178 if (!q || q->realtime) {
02179
02180
02181
02182
02183
02184
02185
02186
02187
02188 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
02189 if (queue_vars) {
02190 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
02191 if (!member_config) {
02192 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
02193 ast_variables_destroy(queue_vars);
02194 return NULL;
02195 }
02196 }
02197 if (q) {
02198 prev_weight = q->weight ? 1 : 0;
02199 }
02200
02201 ao2_lock(queues);
02202
02203 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
02204 if (member_config) {
02205 ast_config_destroy(member_config);
02206 }
02207 if (queue_vars) {
02208 ast_variables_destroy(queue_vars);
02209 }
02210
02211 if (q) {
02212 if (!q->weight && prev_weight) {
02213 ast_atomic_fetchadd_int(&use_weight, -1);
02214 }
02215 if (q->weight && !prev_weight) {
02216 ast_atomic_fetchadd_int(&use_weight, +1);
02217 }
02218 }
02219
02220 ao2_unlock(queues);
02221
02222 } else {
02223 update_realtime_members(q);
02224 }
02225 return q;
02226 }
02227
02228 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
02229 {
02230 int ret = -1;
02231
02232 if (ast_strlen_zero(mem->rt_uniqueid))
02233 return ret;
02234
02235 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
02236 ret = 0;
02237
02238 return ret;
02239 }
02240
02241
02242 static void update_realtime_members(struct call_queue *q)
02243 {
02244 struct ast_config *member_config = NULL;
02245 struct member *m;
02246 char *interface = NULL;
02247 struct ao2_iterator mem_iter;
02248
02249 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
02250
02251 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
02252 return;
02253 }
02254
02255 ao2_lock(queues);
02256 ao2_lock(q);
02257
02258
02259 mem_iter = ao2_iterator_init(q->members, 0);
02260 while ((m = ao2_iterator_next(&mem_iter))) {
02261 if (m->realtime)
02262 m->dead = 1;
02263 ao2_ref(m, -1);
02264 }
02265 ao2_iterator_destroy(&mem_iter);
02266
02267 while ((interface = ast_category_browse(member_config, interface))) {
02268 rt_handle_member_record(q, interface,
02269 ast_variable_retrieve(member_config, interface, "uniqueid"),
02270 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
02271 ast_variable_retrieve(member_config, interface, "penalty"),
02272 ast_variable_retrieve(member_config, interface, "paused"),
02273 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
02274 }
02275
02276
02277 mem_iter = ao2_iterator_init(q->members, 0);
02278 while ((m = ao2_iterator_next(&mem_iter))) {
02279 if (m->dead) {
02280 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02281 ao2_unlink(q->members, m);
02282 q->membercount--;
02283 }
02284 ao2_ref(m, -1);
02285 }
02286 ao2_iterator_destroy(&mem_iter);
02287 ao2_unlock(q);
02288 ao2_unlock(queues);
02289 ast_config_destroy(member_config);
02290 }
02291
02292 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
02293 {
02294 struct call_queue *q;
02295 struct queue_ent *cur, *prev = NULL;
02296 int res = -1;
02297 int pos = 0;
02298 int inserted = 0;
02299
02300 if (!(q = load_realtime_queue(queuename)))
02301 return res;
02302
02303 ao2_lock(queues);
02304 ao2_lock(q);
02305
02306
02307 if (q->joinempty) {
02308 int status = 0;
02309 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
02310 *reason = QUEUE_JOINEMPTY;
02311 ao2_unlock(q);
02312 ao2_unlock(queues);
02313 return res;
02314 }
02315 }
02316 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
02317 *reason = QUEUE_FULL;
02318 else if (*reason == QUEUE_UNKNOWN) {
02319
02320
02321
02322 inserted = 0;
02323 prev = NULL;
02324 cur = q->head;
02325 while (cur) {
02326
02327
02328
02329 if ((!inserted) && (qe->prio > cur->prio)) {
02330 insert_entry(q, prev, qe, &pos);
02331 inserted = 1;
02332 }
02333
02334
02335
02336 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
02337 insert_entry(q, prev, qe, &pos);
02338
02339 if (position < pos) {
02340 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
02341 }
02342 inserted = 1;
02343 }
02344 cur->pos = ++pos;
02345 prev = cur;
02346 cur = cur->next;
02347 }
02348
02349 if (!inserted)
02350 insert_entry(q, prev, qe, &pos);
02351 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
02352 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
02353 ast_copy_string(qe->context, q->context, sizeof(qe->context));
02354 q->count++;
02355 res = 0;
02356 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
02357 "Channel: %s\r\nCallerIDNum: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
02358 qe->chan->name,
02359 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
02360 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
02361 q->name, qe->pos, q->count, qe->chan->uniqueid );
02362 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
02363 }
02364 ao2_unlock(q);
02365 ao2_unlock(queues);
02366
02367 return res;
02368 }
02369
02370 static int play_file(struct ast_channel *chan, const char *filename)
02371 {
02372 int res;
02373
02374 if (ast_strlen_zero(filename)) {
02375 return 0;
02376 }
02377
02378 if (!ast_fileexists(filename, NULL, chan->language)) {
02379 return 0;
02380 }
02381
02382 ast_stopstream(chan);
02383
02384 res = ast_streamfile(chan, filename, chan->language);
02385 if (!res)
02386 res = ast_waitstream(chan, AST_DIGIT_ANY);
02387
02388 ast_stopstream(chan);
02389
02390 return res;
02391 }
02392
02393
02394
02395
02396
02397
02398 static int valid_exit(struct queue_ent *qe, char digit)
02399 {
02400 int digitlen = strlen(qe->digits);
02401
02402
02403 if (digitlen < sizeof(qe->digits) - 2) {
02404 qe->digits[digitlen] = digit;
02405 qe->digits[digitlen + 1] = '\0';
02406 } else {
02407 qe->digits[0] = '\0';
02408 return 0;
02409 }
02410
02411
02412 if (ast_strlen_zero(qe->context))
02413 return 0;
02414
02415
02416 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
02417 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) {
02418 qe->digits[0] = '\0';
02419 return 0;
02420 }
02421
02422
02423 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
02424 qe->valid_digits = 1;
02425
02426 return 1;
02427 }
02428
02429 return 0;
02430 }
02431
02432 static int say_position(struct queue_ent *qe, int ringing)
02433 {
02434 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
02435 int say_thanks = 1;
02436 time_t now;
02437
02438
02439 time(&now);
02440 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
02441 return 0;
02442
02443
02444 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
02445 return 0;
02446
02447 if (ringing) {
02448 ast_indicate(qe->chan,-1);
02449 } else {
02450 ast_moh_stop(qe->chan);
02451 }
02452
02453 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
02454 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
02455 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
02456 qe->pos <= qe->parent->announcepositionlimit))
02457 announceposition = 1;
02458
02459
02460 if (announceposition == 1) {
02461
02462 if (qe->pos == 1) {
02463 res = play_file(qe->chan, qe->parent->sound_next);
02464 if (res)
02465 goto playout;
02466 else
02467 goto posout;
02468 } else {
02469 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
02470
02471 res = play_file(qe->chan, qe->parent->queue_quantity1);
02472 if (res)
02473 goto playout;
02474 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL);
02475 if (res)
02476 goto playout;
02477 } else {
02478
02479 res = play_file(qe->chan, qe->parent->sound_thereare);
02480 if (res)
02481 goto playout;
02482 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL);
02483 if (res)
02484 goto playout;
02485 }
02486 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
02487
02488 res = play_file(qe->chan, qe->parent->queue_quantity2);
02489 if (res)
02490 goto playout;
02491 } else {
02492 res = play_file(qe->chan, qe->parent->sound_calls);
02493 if (res)
02494 goto playout;
02495 }
02496 }
02497 }
02498
02499 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
02500
02501
02502 if (qe->parent->roundingseconds) {
02503 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
02504 avgholdsecs *= qe->parent->roundingseconds;
02505 } else {
02506 avgholdsecs = 0;
02507 }
02508
02509 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
02510
02511
02512
02513 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
02514 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
02515 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
02516 res = play_file(qe->chan, qe->parent->sound_holdtime);
02517 if (res)
02518 goto playout;
02519
02520 if (avgholdmins >= 1) {
02521 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
02522 if (res)
02523 goto playout;
02524
02525 if (avgholdmins == 1) {
02526 res = play_file(qe->chan, qe->parent->sound_minute);
02527 if (res)
02528 goto playout;
02529 } else {
02530 res = play_file(qe->chan, qe->parent->sound_minutes);
02531 if (res)
02532 goto playout;
02533 }
02534 }
02535 if (avgholdsecs >= 1) {
02536 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
02537 if (res)
02538 goto playout;
02539
02540 res = play_file(qe->chan, qe->parent->sound_seconds);
02541 if (res)
02542 goto playout;
02543 }
02544 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
02545 say_thanks = 0;
02546 }
02547
02548 posout:
02549 if (qe->parent->announceposition) {
02550 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
02551 qe->chan->name, qe->parent->name, qe->pos);
02552 }
02553 if (say_thanks) {
02554 res = play_file(qe->chan, qe->parent->sound_thanks);
02555 }
02556 playout:
02557
02558 if ((res > 0 && !valid_exit(qe, res)))
02559 res = 0;
02560
02561
02562 qe->last_pos = now;
02563 qe->last_pos_said = qe->pos;
02564
02565
02566 if (!res) {
02567 if (ringing) {
02568 ast_indicate(qe->chan, AST_CONTROL_RINGING);
02569 } else {
02570 ast_moh_start(qe->chan, qe->moh, NULL);
02571 }
02572 }
02573 return res;
02574 }
02575
02576 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
02577 {
02578 int oldvalue;
02579
02580
02581
02582
02583
02584 ao2_lock(qe->parent);
02585 oldvalue = qe->parent->holdtime;
02586 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
02587 ao2_unlock(qe->parent);
02588 }
02589
02590
02591
02592
02593
02594
02595 static void leave_queue(struct queue_ent *qe)
02596 {
02597 struct call_queue *q;
02598 struct queue_ent *current, *prev = NULL;
02599 struct penalty_rule *pr_iter;
02600 int pos = 0;
02601
02602 if (!(q = qe->parent))
02603 return;
02604 queue_t_ref(q, "Copy queue pointer from queue entry");
02605 ao2_lock(q);
02606
02607 prev = NULL;
02608 for (current = q->head; current; current = current->next) {
02609 if (current == qe) {
02610 char posstr[20];
02611 q->count--;
02612
02613
02614 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
02615 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
02616 qe->chan->name, q->name, q->count, qe->pos, qe->chan->uniqueid);
02617 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
02618
02619 if (prev)
02620 prev->next = current->next;
02621 else
02622 q->head = current->next;
02623
02624 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
02625 ast_free(pr_iter);
02626 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
02627 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
02628 } else {
02629
02630 current->pos = ++pos;
02631 prev = current;
02632 }
02633 }
02634 ao2_unlock(q);
02635
02636
02637 if (q->realtime) {
02638 struct ast_variable *var;
02639 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
02640 q->dead = 1;
02641 } else {
02642 ast_variables_destroy(var);
02643 }
02644 }
02645
02646 if (q->dead) {
02647
02648 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
02649 }
02650
02651 queue_t_unref(q, "Expire copied reference");
02652 }
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662
02663 static void callattempt_free(struct callattempt *doomed)
02664 {
02665 if (doomed->member) {
02666 ao2_ref(doomed->member, -1);
02667 }
02668 ast_party_connected_line_free(&doomed->connected);
02669 ast_free(doomed);
02670 }
02671
02672
02673 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
02674 {
02675 struct callattempt *oo;
02676
02677 while (outgoing) {
02678
02679
02680 if (outgoing->chan && (outgoing->chan != exception)) {
02681 if (exception || cancel_answered_elsewhere)
02682 ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
02683 ast_hangup(outgoing->chan);
02684 }
02685 oo = outgoing;
02686 outgoing = outgoing->q_next;
02687 ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
02688 callattempt_free(oo);
02689 }
02690 }
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700 static int num_available_members(struct call_queue *q)
02701 {
02702 struct member *mem;
02703 int avl = 0;
02704 struct ao2_iterator mem_iter;
02705
02706 mem_iter = ao2_iterator_init(q->members, 0);
02707 while ((mem = ao2_iterator_next(&mem_iter))) {
02708 switch (mem->status) {
02709 case AST_DEVICE_INUSE:
02710 if (!q->ringinuse)
02711 break;
02712
02713 case AST_DEVICE_NOT_INUSE:
02714 case AST_DEVICE_UNKNOWN:
02715 if (!mem->paused) {
02716 avl++;
02717 }
02718 break;
02719 }
02720 ao2_ref(mem, -1);
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
02733 break;
02734 }
02735 }
02736 ao2_iterator_destroy(&mem_iter);
02737
02738 return avl;
02739 }
02740
02741
02742
02743 static int compare_weight(struct call_queue *rq, struct member *member)
02744 {
02745 struct call_queue *q;
02746 struct member *mem;
02747 int found = 0;
02748 struct ao2_iterator queue_iter;
02749
02750
02751
02752 queue_iter = ao2_iterator_init(queues, 0);
02753 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
02754 if (q == rq) {
02755 queue_t_unref(q, "Done with iterator");
02756 continue;
02757 }
02758 ao2_lock(q);
02759 if (q->count && q->members) {
02760 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
02761 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
02762 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
02763 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);
02764 found = 1;
02765 }
02766 ao2_ref(mem, -1);
02767 }
02768 }
02769 ao2_unlock(q);
02770 queue_t_unref(q, "Done with iterator");
02771 if (found) {
02772 break;
02773 }
02774 }
02775 ao2_iterator_destroy(&queue_iter);
02776 return found;
02777 }
02778
02779
02780 static void do_hang(struct callattempt *o)
02781 {
02782 o->stillgoing = 0;
02783 ast_hangup(o->chan);
02784 o->chan = NULL;
02785 }
02786
02787
02788 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
02789 {
02790 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
02791 const char *tmp;
02792
02793 if (pbx_builtin_serialize_variables(chan, &buf)) {
02794 int i, j;
02795
02796
02797 strcpy(vars, "Variable: ");
02798 tmp = ast_str_buffer(buf);
02799
02800 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
02801 vars[j] = tmp[i];
02802
02803 if (tmp[i + 1] == '\0')
02804 break;
02805 if (tmp[i] == '\n') {
02806 vars[j++] = '\r';
02807 vars[j++] = '\n';
02808
02809 ast_copy_string(&(vars[j]), "Variable: ", len - j);
02810 j += 9;
02811 }
02812 }
02813 if (j > len - 3)
02814 j = len - 3;
02815 vars[j++] = '\r';
02816 vars[j++] = '\n';
02817 vars[j] = '\0';
02818 } else {
02819
02820 *vars = '\0';
02821 }
02822 return vars;
02823 }
02824
02825
02826
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
02840 {
02841 int res;
02842 int status;
02843 char tech[256];
02844 char *location;
02845 const char *macrocontext, *macroexten;
02846
02847
02848 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
02849 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
02850 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
02851 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
02852 if (qe->chan->cdr)
02853 ast_cdr_busy(qe->chan->cdr);
02854 tmp->stillgoing = 0;
02855 (*busies)++;
02856 return 0;
02857 }
02858
02859 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
02860 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
02861 if (qe->chan->cdr)
02862 ast_cdr_busy(qe->chan->cdr);
02863 tmp->stillgoing = 0;
02864 return 0;
02865 }
02866
02867 if (tmp->member->paused) {
02868 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
02869 if (qe->chan->cdr)
02870 ast_cdr_busy(qe->chan->cdr);
02871 tmp->stillgoing = 0;
02872 return 0;
02873 }
02874 if (use_weight && compare_weight(qe->parent,tmp->member)) {
02875 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
02876 if (qe->chan->cdr)
02877 ast_cdr_busy(qe->chan->cdr);
02878 tmp->stillgoing = 0;
02879 (*busies)++;
02880 return 0;
02881 }
02882
02883 ast_copy_string(tech, tmp->interface, sizeof(tech));
02884 if ((location = strchr(tech, '/')))
02885 *location++ = '\0';
02886 else
02887 location = "";
02888
02889
02890 tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
02891 if (!tmp->chan) {
02892 if (qe->chan->cdr)
02893 ast_cdr_busy(qe->chan->cdr);
02894 tmp->stillgoing = 0;
02895
02896 ao2_lock(qe->parent);
02897 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
02898 qe->parent->rrpos++;
02899 qe->linpos++;
02900 ao2_unlock(qe->parent);
02901
02902 (*busies)++;
02903 return 0;
02904 }
02905
02906 ast_channel_lock(tmp->chan);
02907 while (ast_channel_trylock(qe->chan)) {
02908 CHANNEL_DEADLOCK_AVOIDANCE(tmp->chan);
02909 }
02910
02911 if (qe->cancel_answered_elsewhere) {
02912 ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
02913 }
02914 tmp->chan->appl = "AppQueue";
02915 tmp->chan->data = "(Outgoing Line)";
02916 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
02917
02918
02919 if (!tmp->chan->caller.id.number.valid) {
02920 if (qe->chan->connected.id.number.valid) {
02921 struct ast_party_caller caller;
02922
02923 ast_party_caller_set_init(&caller, &tmp->chan->caller);
02924 caller.id = qe->chan->connected.id;
02925 caller.ani = qe->chan->connected.ani;
02926 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
02927 } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) {
02928 ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL);
02929 } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
02930 ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL);
02931 }
02932 tmp->dial_callerid_absent = 1;
02933 }
02934
02935 ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
02936
02937 tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select;
02938
02939 ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller);
02940
02941
02942 ast_channel_inherit_variables(qe->chan, tmp->chan);
02943 ast_channel_datastore_inherit(qe->chan, tmp->chan);
02944
02945
02946 tmp->chan->adsicpe = qe->chan->adsicpe;
02947
02948
02949 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
02950 ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
02951 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
02952 if (!ast_strlen_zero(macroexten))
02953 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
02954 else
02955 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
02956 if (ast_cdr_isset_unanswered()) {
02957
02958
02959 ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
02960 strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
02961 strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
02962 strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
02963 strcpy(tmp->chan->cdr->dst, qe->chan->exten);
02964 strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
02965 strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
02966 strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
02967 tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
02968 strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
02969 strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
02970 }
02971
02972
02973 if ((res = ast_call(tmp->chan, location, 0))) {
02974
02975 ast_debug(1, "ast call on peer returned %d\n", res);
02976 ast_verb(3, "Couldn't call %s\n", tmp->interface);
02977 ast_channel_unlock(tmp->chan);
02978 ast_channel_unlock(qe->chan);
02979 do_hang(tmp);
02980 (*busies)++;
02981 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
02982 return 0;
02983 } else if (qe->parent->eventwhencalled) {
02984 char vars[2048];
02985
02986 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
02987 "Queue: %s\r\n"
02988 "AgentCalled: %s\r\n"
02989 "AgentName: %s\r\n"
02990 "ChannelCalling: %s\r\n"
02991 "DestinationChannel: %s\r\n"
02992 "CallerIDNum: %s\r\n"
02993 "CallerIDName: %s\r\n"
02994 "Context: %s\r\n"
02995 "Extension: %s\r\n"
02996 "Priority: %d\r\n"
02997 "Uniqueid: %s\r\n"
02998 "%s",
02999 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
03000 S_COR(tmp->chan->caller.id.number.valid, tmp->chan->caller.id.number.str, "unknown"),
03001 S_COR(tmp->chan->caller.id.name.valid, tmp->chan->caller.id.name.str, "unknown"),
03002 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
03003 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03004 ast_verb(3, "Called %s\n", tmp->interface);
03005 }
03006 ast_channel_unlock(tmp->chan);
03007 ast_channel_unlock(qe->chan);
03008
03009 update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03010 return 1;
03011 }
03012
03013
03014 static struct callattempt *find_best(struct callattempt *outgoing)
03015 {
03016 struct callattempt *best = NULL, *cur;
03017
03018 for (cur = outgoing; cur; cur = cur->q_next) {
03019 if (cur->stillgoing &&
03020 !cur->chan &&
03021 (!best || cur->metric < best->metric)) {
03022 best = cur;
03023 }
03024 }
03025
03026 return best;
03027 }
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
03040 {
03041 int ret = 0;
03042
03043 while (ret == 0) {
03044 struct callattempt *best = find_best(outgoing);
03045 if (!best) {
03046 ast_debug(1, "Nobody left to try ringing in queue\n");
03047 break;
03048 }
03049 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03050 struct callattempt *cur;
03051
03052 for (cur = outgoing; cur; cur = cur->q_next) {
03053 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
03054 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
03055 ret |= ring_entry(qe, cur, busies);
03056 }
03057 }
03058 } else {
03059
03060 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
03061 ret = ring_entry(qe, best, busies);
03062 }
03063
03064
03065 if (qe->expire && (time(NULL) >= qe->expire)) {
03066 ast_debug(1, "Queue timed out while ringing members.\n");
03067 ret = 0;
03068 break;
03069 }
03070 }
03071
03072 return ret;
03073 }
03074
03075
03076 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
03077 {
03078 struct callattempt *best = find_best(outgoing);
03079
03080 if (best) {
03081
03082 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03083 qe->parent->rrpos = best->metric % 1000;
03084 } else {
03085
03086 if (qe->parent->wrapped) {
03087
03088 qe->parent->rrpos = 0;
03089 } else {
03090
03091 qe->parent->rrpos++;
03092 }
03093 }
03094 qe->parent->wrapped = 0;
03095
03096 return 0;
03097 }
03098
03099
03100 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
03101 {
03102 struct callattempt *best = find_best(outgoing);
03103
03104 if (best) {
03105
03106 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03107 qe->linpos = best->metric % 1000;
03108 } else {
03109
03110 if (qe->linwrapped) {
03111
03112 qe->linpos = 0;
03113 } else {
03114
03115 qe->linpos++;
03116 }
03117 }
03118 qe->linwrapped = 0;
03119
03120 return 0;
03121 }
03122
03123
03124 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
03125 {
03126 int res = 0;
03127 time_t now;
03128
03129
03130 time(&now);
03131
03132
03133 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
03134 return 0;
03135
03136
03137 if (ringing)
03138 ast_indicate(qe->chan,-1);
03139 else
03140 ast_moh_stop(qe->chan);
03141
03142 ast_verb(3, "Playing periodic announcement\n");
03143
03144 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
03145 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
03146 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
03147 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
03148 qe->last_periodic_announce_sound = 0;
03149 }
03150
03151
03152 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
03153
03154 if (res > 0 && !valid_exit(qe, res))
03155 res = 0;
03156
03157
03158 if (!res) {
03159 if (ringing)
03160 ast_indicate(qe->chan, AST_CONTROL_RINGING);
03161 else
03162 ast_moh_start(qe->chan, qe->moh, NULL);
03163 }
03164
03165
03166 if (qe->parent->relativeperiodicannounce)
03167 time(&qe->last_periodic_announce_time);
03168 else
03169 qe->last_periodic_announce_time = now;
03170
03171
03172 if (!qe->parent->randomperiodicannounce) {
03173 qe->last_periodic_announce_sound++;
03174 }
03175
03176 return res;
03177 }
03178
03179
03180 static void record_abandoned(struct queue_ent *qe)
03181 {
03182 set_queue_variables(qe->parent, qe->chan);
03183 ao2_lock(qe->parent);
03184 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
03185 "Queue: %s\r\n"
03186 "Uniqueid: %s\r\n"
03187 "Position: %d\r\n"
03188 "OriginalPosition: %d\r\n"
03189 "HoldTime: %d\r\n",
03190 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
03191
03192 qe->parent->callsabandoned++;
03193 ao2_unlock(qe->parent);
03194 }
03195
03196
03197 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
03198 {
03199 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
03200
03201
03202 if (qe->ring_when_ringing) {
03203 ast_indicate(qe->chan, -1);
03204 ast_moh_start(qe->chan, qe->moh, NULL);
03205 }
03206
03207 if (qe->parent->eventwhencalled) {
03208 char vars[2048];
03209
03210 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
03211 "Queue: %s\r\n"
03212 "Uniqueid: %s\r\n"
03213 "Channel: %s\r\n"
03214 "Member: %s\r\n"
03215 "MemberName: %s\r\n"
03216 "Ringtime: %d\r\n"
03217 "%s",
03218 qe->parent->name,
03219 qe->chan->uniqueid,
03220 qe->chan->name,
03221 interface,
03222 membername,
03223 rnatime,
03224 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03225 }
03226 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
03227 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
03228 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
03229 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
03230 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
03231 interface, qe->parent->name);
03232 } else {
03233 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
03234 }
03235 } else {
03236
03237
03238 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
03239 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
03240 interface, qe->parent->name);
03241 } else {
03242 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
03243 }
03244 }
03245 }
03246 return;
03247 }
03248
03249 #define AST_MAX_WATCHERS 256
03250
03251
03252
03253
03254
03255
03256
03257
03258
03259
03260
03261
03262
03263
03264 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int update_connectedline)
03265 {
03266 const char *queue = qe->parent->name;
03267 struct callattempt *o, *start = NULL, *prev = NULL;
03268 int res;
03269 int status;
03270 int numbusies = prebusies;
03271 int numnochan = 0;
03272 int stillgoing = 0;
03273 int orig = *to;
03274 struct ast_frame *f;
03275 struct callattempt *peer = NULL;
03276 struct ast_channel *winner;
03277 struct ast_channel *in = qe->chan;
03278 char on[80] = "";
03279 char membername[80] = "";
03280 long starttime = 0;
03281 long endtime = 0;
03282 #ifdef HAVE_EPOLL
03283 struct callattempt *epollo;
03284 #endif
03285 struct ast_party_connected_line connected_caller;
03286 char *inchan_name;
03287
03288 ast_party_connected_line_init(&connected_caller);
03289
03290 ast_channel_lock(qe->chan);
03291 inchan_name = ast_strdupa(qe->chan->name);
03292 ast_channel_unlock(qe->chan);
03293
03294 starttime = (long) time(NULL);
03295 #ifdef HAVE_EPOLL
03296 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03297 if (epollo->chan)
03298 ast_poll_channel_add(in, epollo->chan);
03299 }
03300 #endif
03301
03302 while (*to && !peer) {
03303 int numlines, retry, pos = 1;
03304 struct ast_channel *watchers[AST_MAX_WATCHERS];
03305 watchers[0] = in;
03306 start = NULL;
03307
03308 for (retry = 0; retry < 2; retry++) {
03309 numlines = 0;
03310 for (o = outgoing; o; o = o->q_next) {
03311 if (o->stillgoing) {
03312 stillgoing = 1;
03313 if (o->chan) {
03314 watchers[pos++] = o->chan;
03315 if (!start)
03316 start = o;
03317 else
03318 prev->call_next = o;
03319 prev = o;
03320 }
03321 }
03322 numlines++;
03323 }
03324 if (pos > 1 || !stillgoing ||
03325 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) )
03326 break;
03327
03328
03329 ring_one(qe, outgoing, &numbusies);
03330
03331 }
03332 if (pos == 1 ) {
03333 if (numlines == (numbusies + numnochan)) {
03334 ast_debug(1, "Everyone is busy at this time\n");
03335 } else {
03336 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
03337 }
03338 *to = 0;
03339 return NULL;
03340 }
03341
03342
03343 winner = ast_waitfor_n(watchers, pos, to);
03344
03345
03346 for (o = start; o; o = o->call_next) {
03347
03348
03349
03350 char ochan_name[AST_CHANNEL_NAME];
03351 if (o->chan) {
03352 ast_channel_lock(o->chan);
03353 ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
03354 ast_channel_unlock(o->chan);
03355 }
03356 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
03357 if (!peer) {
03358 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03359 if (update_connectedline) {
03360 if (o->pending_connected_update) {
03361 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03362 ast_channel_update_connected_line(in, &o->connected, NULL);
03363 }
03364 } else if (!o->dial_callerid_absent) {
03365 ast_channel_lock(o->chan);
03366 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03367 ast_channel_unlock(o->chan);
03368 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03369 ast_channel_update_connected_line(in, &connected_caller, NULL);
03370 ast_party_connected_line_free(&connected_caller);
03371 }
03372 }
03373 if (o->aoc_s_rate_list) {
03374 size_t encoded_size;
03375 struct ast_aoc_encoded *encoded;
03376 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03377 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03378 ast_aoc_destroy_encoded(encoded);
03379 }
03380 }
03381 peer = o;
03382 }
03383 } else if (o->chan && (o->chan == winner)) {
03384
03385 ast_copy_string(on, o->member->interface, sizeof(on));
03386 ast_copy_string(membername, o->member->membername, sizeof(membername));
03387
03388 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
03389 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
03390 numnochan++;
03391 do_hang(o);
03392 winner = NULL;
03393 continue;
03394 } else if (!ast_strlen_zero(o->chan->call_forward)) {
03395 struct ast_channel *original = o->chan;
03396 char tmpchan[256];
03397 char *stuff;
03398 char *tech;
03399
03400 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
03401 if ((stuff = strchr(tmpchan, '/'))) {
03402 *stuff++ = '\0';
03403 tech = tmpchan;
03404 } else {
03405 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
03406 stuff = tmpchan;
03407 tech = "Local";
03408 }
03409
03410 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
03411
03412
03413 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
03414
03415 o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
03416 if (!o->chan) {
03417 ast_log(LOG_NOTICE,
03418 "Forwarding failed to create channel to dial '%s/%s'\n",
03419 tech, stuff);
03420 o->stillgoing = 0;
03421 numnochan++;
03422 } else {
03423 struct ast_party_redirecting redirecting;
03424
03425 ast_channel_lock(o->chan);
03426 while (ast_channel_trylock(in)) {
03427 CHANNEL_DEADLOCK_AVOIDANCE(o->chan);
03428 }
03429 ast_channel_inherit_variables(in, o->chan);
03430 ast_channel_datastore_inherit(in, o->chan);
03431
03432 ast_string_field_set(o->chan, accountcode, in->accountcode);
03433
03434 ast_channel_set_redirecting(o->chan, &original->redirecting, NULL);
03435 if (!o->chan->redirecting.from.number.valid
03436 || ast_strlen_zero(o->chan->redirecting.from.number.str)) {
03437
03438
03439
03440
03441 ast_party_number_free(&o->chan->redirecting.from.number);
03442 ast_party_number_init(&o->chan->redirecting.from.number);
03443 o->chan->redirecting.from.number.valid = 1;
03444 o->chan->redirecting.from.number.str =
03445 ast_strdup(S_OR(in->macroexten, in->exten));
03446 }
03447
03448 o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
03449
03450 ast_party_caller_copy(&o->chan->caller, &in->caller);
03451 ast_party_connected_line_copy(&o->chan->connected, &original->connected);
03452
03453
03454
03455
03456
03457
03458
03459
03460 ast_party_redirecting_init(&redirecting);
03461 ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
03462 ast_channel_unlock(o->chan);
03463 res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0);
03464 if (res) {
03465 ast_channel_update_redirecting(in, &redirecting, NULL);
03466 }
03467 ast_party_redirecting_free(&redirecting);
03468 ast_channel_unlock(in);
03469
03470 update_connectedline = 1;
03471
03472 if (ast_call(o->chan, stuff, 0)) {
03473 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
03474 tech, stuff);
03475 do_hang(o);
03476 numnochan++;
03477 }
03478 }
03479
03480 ast_hangup(winner);
03481 continue;
03482 }
03483 f = ast_read(winner);
03484 if (f) {
03485 if (f->frametype == AST_FRAME_CONTROL) {
03486 switch (f->subclass.integer) {
03487 case AST_CONTROL_ANSWER:
03488
03489 if (!peer) {
03490 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03491 if (update_connectedline) {
03492 if (o->pending_connected_update) {
03493 if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03494 ast_channel_update_connected_line(in, &o->connected, NULL);
03495 }
03496 } else if (!o->dial_callerid_absent) {
03497 ast_channel_lock(o->chan);
03498 ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03499 ast_channel_unlock(o->chan);
03500 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03501 ast_channel_update_connected_line(in, &connected_caller, NULL);
03502 ast_party_connected_line_free(&connected_caller);
03503 }
03504 }
03505 if (o->aoc_s_rate_list) {
03506 size_t encoded_size;
03507 struct ast_aoc_encoded *encoded;
03508 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03509 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03510 ast_aoc_destroy_encoded(encoded);
03511 }
03512 }
03513 peer = o;
03514 }
03515 break;
03516 case AST_CONTROL_BUSY:
03517 ast_verb(3, "%s is busy\n", ochan_name);
03518 if (in->cdr)
03519 ast_cdr_busy(in->cdr);
03520 do_hang(o);
03521 endtime = (long) time(NULL);
03522 endtime -= starttime;
03523 rna(endtime * 1000, qe, on, membername, 0);
03524 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03525 if (qe->parent->timeoutrestart)
03526 *to = orig;
03527
03528 if (*to > 500) {
03529 ring_one(qe, outgoing, &numbusies);
03530 starttime = (long) time(NULL);
03531 }
03532 }
03533 numbusies++;
03534 break;
03535 case AST_CONTROL_CONGESTION:
03536 ast_verb(3, "%s is circuit-busy\n", ochan_name);
03537 if (in->cdr)
03538 ast_cdr_busy(in->cdr);
03539 endtime = (long) time(NULL);
03540 endtime -= starttime;
03541 rna(endtime * 1000, qe, on, membername, 0);
03542 do_hang(o);
03543 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03544 if (qe->parent->timeoutrestart)
03545 *to = orig;
03546 if (*to > 500) {
03547 ring_one(qe, outgoing, &numbusies);
03548 starttime = (long) time(NULL);
03549 }
03550 }
03551 numbusies++;
03552 break;
03553 case AST_CONTROL_RINGING:
03554 ast_verb(3, "%s is ringing\n", ochan_name);
03555
03556
03557 if (qe->ring_when_ringing) {
03558 ast_moh_stop(qe->chan);
03559 ast_indicate(qe->chan, AST_CONTROL_RINGING);
03560 }
03561 break;
03562 case AST_CONTROL_OFFHOOK:
03563
03564 break;
03565 case AST_CONTROL_CONNECTED_LINE:
03566 if (!update_connectedline) {
03567 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
03568 } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03569 struct ast_party_connected_line connected;
03570 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
03571 ast_party_connected_line_set_init(&connected, &o->connected);
03572 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
03573 ast_party_connected_line_set(&o->connected, &connected, NULL);
03574 ast_party_connected_line_free(&connected);
03575 o->pending_connected_update = 1;
03576 } else {
03577 if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
03578 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
03579 }
03580 }
03581 break;
03582 case AST_CONTROL_AOC:
03583 {
03584 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
03585 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
03586 ast_aoc_destroy_decoded(o->aoc_s_rate_list);
03587 o->aoc_s_rate_list = decoded;
03588 } else {
03589 ast_aoc_destroy_decoded(decoded);
03590 }
03591 }
03592 break;
03593 case AST_CONTROL_REDIRECTING:
03594 if (!update_connectedline) {
03595 ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
03596 } else {
03597 ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
03598 if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
03599 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
03600 }
03601 }
03602 break;
03603 default:
03604 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
03605 break;
03606 }
03607 }
03608 ast_frfree(f);
03609 } else {
03610 endtime = (long) time(NULL) - starttime;
03611 rna(endtime * 1000, qe, on, membername, 1);
03612 do_hang(o);
03613 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03614 if (qe->parent->timeoutrestart)
03615 *to = orig;
03616 if (*to > 500) {
03617 ring_one(qe, outgoing, &numbusies);
03618 starttime = (long) time(NULL);
03619 }
03620 }
03621 }
03622 }
03623 }
03624
03625
03626 if (winner == in) {
03627 f = ast_read(in);
03628 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
03629
03630 *to = -1;
03631 if (f) {
03632 if (f->data.uint32) {
03633 in->hangupcause = f->data.uint32;
03634 }
03635 ast_frfree(f);
03636 }
03637 return NULL;
03638 }
03639 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
03640 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
03641 *to = 0;
03642 ast_frfree(f);
03643 return NULL;
03644 }
03645 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
03646 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
03647 *to = 0;
03648 *digit = f->subclass.integer;
03649 ast_frfree(f);
03650 return NULL;
03651 }
03652 ast_frfree(f);
03653 }
03654 if (!*to) {
03655 for (o = start; o; o = o->call_next)
03656 rna(orig, qe, o->interface, o->member->membername, 1);
03657 }
03658 }
03659
03660 #ifdef HAVE_EPOLL
03661 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03662 if (epollo->chan)
03663 ast_poll_channel_del(in, epollo->chan);
03664 }
03665 #endif
03666
03667 return peer;
03668 }
03669
03670
03671
03672
03673
03674
03675
03676
03677
03678
03679
03680
03681 static int is_our_turn(struct queue_ent *qe)
03682 {
03683 struct queue_ent *ch;
03684 int res;
03685 int avl;
03686 int idx = 0;
03687
03688 ao2_lock(qe->parent);
03689
03690 avl = num_available_members(qe->parent);
03691
03692 ch = qe->parent->head;
03693
03694 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
03695
03696 while ((idx < avl) && (ch) && (ch != qe)) {
03697 if (!ch->pending)
03698 idx++;
03699 ch = ch->next;
03700 }
03701
03702 ao2_unlock(qe->parent);
03703
03704
03705
03706
03707 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
03708 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
03709 res = 1;
03710 } else {
03711 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
03712 res = 0;
03713 }
03714
03715 return res;
03716 }
03717
03718
03719
03720
03721
03722
03723
03724 static void update_qe_rule(struct queue_ent *qe)
03725 {
03726 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
03727 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
03728 char max_penalty_str[20], min_penalty_str[20];
03729
03730 if (max_penalty < 0)
03731 max_penalty = 0;
03732 if (min_penalty < 0)
03733 min_penalty = 0;
03734 if (min_penalty > max_penalty)
03735 min_penalty = max_penalty;
03736 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
03737 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
03738 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
03739 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
03740 qe->max_penalty = max_penalty;
03741 qe->min_penalty = min_penalty;
03742 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);
03743 qe->pr = AST_LIST_NEXT(qe->pr, list);
03744 }
03745
03746
03747
03748
03749
03750
03751
03752
03753
03754
03755
03756 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
03757 {
03758 int res = 0;
03759
03760
03761 for (;;) {
03762
03763 if (is_our_turn(qe))
03764 break;
03765
03766
03767 if (qe->expire && (time(NULL) >= qe->expire)) {
03768 *reason = QUEUE_TIMEOUT;
03769 break;
03770 }
03771
03772 if (qe->parent->leavewhenempty) {
03773 int status = 0;
03774
03775 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
03776 *reason = QUEUE_LEAVEEMPTY;
03777 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
03778 leave_queue(qe);
03779 break;
03780 }
03781 }
03782
03783
03784 if (qe->parent->announcefrequency &&
03785 (res = say_position(qe,ringing)))
03786 break;
03787
03788
03789 if (qe->expire && (time(NULL) >= qe->expire)) {
03790 *reason = QUEUE_TIMEOUT;
03791 break;
03792 }
03793
03794
03795 if (qe->parent->periodicannouncefrequency &&
03796 (res = say_periodic_announcement(qe,ringing)))
03797 break;
03798
03799
03800 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
03801 update_qe_rule(qe);
03802 }
03803
03804
03805 if (qe->expire && (time(NULL) >= qe->expire)) {
03806 *reason = QUEUE_TIMEOUT;
03807 break;
03808 }
03809
03810
03811 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
03812 if (res > 0 && !valid_exit(qe, res))
03813 res = 0;
03814 else
03815 break;
03816 }
03817
03818
03819 if (qe->expire && (time(NULL) >= qe->expire)) {
03820 *reason = QUEUE_TIMEOUT;
03821 break;
03822 }
03823 }
03824
03825 return res;
03826 }
03827
03828
03829
03830
03831
03832 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
03833 {
03834 int oldtalktime;
03835
03836 struct member *mem;
03837 struct call_queue *qtmp;
03838 struct ao2_iterator queue_iter;
03839
03840 if (shared_lastcall) {
03841 queue_iter = ao2_iterator_init(queues, 0);
03842 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
03843 ao2_lock(qtmp);
03844 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
03845 time(&mem->lastcall);
03846 mem->calls++;
03847 mem->lastqueue = q;
03848 ao2_ref(mem, -1);
03849 }
03850 ao2_unlock(qtmp);
03851 queue_t_unref(qtmp, "Done with iterator");
03852 }
03853 ao2_iterator_destroy(&queue_iter);
03854 } else {
03855 ao2_lock(q);
03856 time(&member->lastcall);
03857 member->calls++;
03858 member->lastqueue = q;
03859 ao2_unlock(q);
03860 }
03861 ao2_lock(q);
03862 q->callscompleted++;
03863 if (callcompletedinsl)
03864 q->callscompletedinsl++;
03865
03866 oldtalktime = q->talktime;
03867 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
03868 ao2_unlock(q);
03869 return 0;
03870 }
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
03881 {
03882
03883 unsigned char usepenalty = (q->membercount <= q->penaltymemberslimit) ? 0 : 1;
03884
03885 if (usepenalty) {
03886 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) ||
03887 (qe->min_penalty && (mem->penalty < qe->min_penalty))) {
03888 return -1;
03889 }
03890 } else {
03891 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
03892 q->membercount, q->penaltymemberslimit);
03893 }
03894
03895 switch (q->strategy) {
03896 case QUEUE_STRATEGY_RINGALL:
03897
03898 tmp->metric = mem->penalty * 1000000 * usepenalty;
03899 break;
03900 case QUEUE_STRATEGY_LINEAR:
03901 if (pos < qe->linpos) {
03902 tmp->metric = 1000 + pos;
03903 } else {
03904 if (pos > qe->linpos)
03905
03906 qe->linwrapped = 1;
03907 tmp->metric = pos;
03908 }
03909 tmp->metric += mem->penalty * 1000000 * usepenalty;
03910 break;
03911 case QUEUE_STRATEGY_RRMEMORY:
03912 if (pos < q->rrpos) {
03913 tmp->metric = 1000 + pos;
03914 } else {
03915 if (pos > q->rrpos)
03916
03917 q->wrapped = 1;
03918 tmp->metric = pos;
03919 }
03920 tmp->metric += mem->penalty * 1000000 * usepenalty;
03921 break;
03922 case QUEUE_STRATEGY_RANDOM:
03923 tmp->metric = ast_random() % 1000;
03924 tmp->metric += mem->penalty * 1000000 * usepenalty;
03925 break;
03926 case QUEUE_STRATEGY_WRANDOM:
03927 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
03928 break;
03929 case QUEUE_STRATEGY_FEWESTCALLS:
03930 tmp->metric = mem->calls;
03931 tmp->metric += mem->penalty * 1000000 * usepenalty;
03932 break;
03933 case QUEUE_STRATEGY_LEASTRECENT:
03934 if (!mem->lastcall)
03935 tmp->metric = 0;
03936 else
03937 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
03938 tmp->metric += mem->penalty * 1000000 * usepenalty;
03939 break;
03940 default:
03941 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
03942 break;
03943 }
03944 return 0;
03945 }
03946
03947 enum agent_complete_reason {
03948 CALLER,
03949 AGENT,
03950 TRANSFER
03951 };
03952
03953
03954 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
03955 const struct ast_channel *peer, const struct member *member, time_t callstart,
03956 char *vars, size_t vars_len, enum agent_complete_reason rsn)
03957 {
03958 const char *reason = NULL;
03959
03960 if (!qe->parent->eventwhencalled)
03961 return;
03962
03963 switch (rsn) {
03964 case CALLER:
03965 reason = "caller";
03966 break;
03967 case AGENT:
03968 reason = "agent";
03969 break;
03970 case TRANSFER:
03971 reason = "transfer";
03972 break;
03973 }
03974
03975 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03976 "Queue: %s\r\n"
03977 "Uniqueid: %s\r\n"
03978 "Channel: %s\r\n"
03979 "Member: %s\r\n"
03980 "MemberName: %s\r\n"
03981 "HoldTime: %ld\r\n"
03982 "TalkTime: %ld\r\n"
03983 "Reason: %s\r\n"
03984 "%s",
03985 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03986 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
03987 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
03988 }
03989
03990 struct queue_transfer_ds {
03991 struct queue_ent *qe;
03992 struct member *member;
03993 time_t starttime;
03994 int callcompletedinsl;
03995 };
03996
03997 static void queue_transfer_destroy(void *data)
03998 {
03999 struct queue_transfer_ds *qtds = data;
04000 ast_free(qtds);
04001 }
04002
04003
04004
04005 static const struct ast_datastore_info queue_transfer_info = {
04006 .type = "queue_transfer",
04007 .chan_fixup = queue_transfer_fixup,
04008 .destroy = queue_transfer_destroy,
04009 };
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019
04020 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
04021 {
04022 struct queue_transfer_ds *qtds = data;
04023 struct queue_ent *qe = qtds->qe;
04024 struct member *member = qtds->member;
04025 time_t callstart = qtds->starttime;
04026 int callcompletedinsl = qtds->callcompletedinsl;
04027 struct ast_datastore *datastore;
04028
04029 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
04030 new_chan->exten, new_chan->context, (long) (callstart - qe->start),
04031 (long) (time(NULL) - callstart), qe->opos);
04032
04033 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
04034
04035
04036 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
04037 ast_channel_datastore_remove(old_chan, datastore);
04038 } else {
04039 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
04040 }
04041 }
04042
04043
04044
04045
04046
04047
04048
04049
04050
04051 static int attended_transfer_occurred(struct ast_channel *chan)
04052 {
04053 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
04054 }
04055
04056
04057
04058 static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
04059 {
04060 struct ast_datastore *ds;
04061 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
04062
04063 if (!qtds) {
04064 ast_log(LOG_WARNING, "Memory allocation error!\n");
04065 return NULL;
04066 }
04067
04068 ast_channel_lock(qe->chan);
04069 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
04070 ast_channel_unlock(qe->chan);
04071 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
04072 return NULL;
04073 }
04074
04075 qtds->qe = qe;
04076
04077 qtds->member = member;
04078 qtds->starttime = starttime;
04079 qtds->callcompletedinsl = callcompletedinsl;
04080 ds->data = qtds;
04081 ast_channel_datastore_add(qe->chan, ds);
04082 ast_channel_unlock(qe->chan);
04083 return ds;
04084 }
04085
04086 struct queue_end_bridge {
04087 struct call_queue *q;
04088 struct ast_channel *chan;
04089 };
04090
04091 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
04092 {
04093 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
04094 ao2_ref(qeb, +1);
04095 qeb->chan = originator;
04096 }
04097
04098 static void end_bridge_callback(void *data)
04099 {
04100 struct queue_end_bridge *qeb = data;
04101 struct call_queue *q = qeb->q;
04102 struct ast_channel *chan = qeb->chan;
04103
04104 if (ao2_ref(qeb, -1) == 1) {
04105 set_queue_variables(q, chan);
04106
04107 queue_t_unref(q, "Expire bridge_config reference");
04108 }
04109 }
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119
04120
04121
04122
04123
04124
04125
04126
04127
04128
04129
04130
04131
04132
04133
04134
04135
04136
04137
04138 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)
04139 {
04140 struct member *cur;
04141 struct callattempt *outgoing = NULL;
04142 int to, orig;
04143 char oldexten[AST_MAX_EXTENSION]="";
04144 char oldcontext[AST_MAX_CONTEXT]="";
04145 char queuename[256]="";
04146 char interfacevar[256]="";
04147 struct ast_channel *peer;
04148 struct ast_channel *which;
04149 struct callattempt *lpeer;
04150 struct member *member;
04151 struct ast_app *application;
04152 int res = 0, bridge = 0;
04153 int numbusies = 0;
04154 int x=0;
04155 char *announce = NULL;
04156 char digit = 0;
04157 time_t callstart;
04158 time_t now = time(NULL);
04159 struct ast_bridge_config bridge_config;
04160 char nondataquality = 1;
04161 char *agiexec = NULL;
04162 char *macroexec = NULL;
04163 char *gosubexec = NULL;
04164 int ret = 0;
04165 const char *monitorfilename;
04166 const char *monitor_exec;
04167 const char *monitor_options;
04168 char tmpid[256], tmpid2[256];
04169 char meid[1024], meid2[1024];
04170 char mixmonargs[1512];
04171 struct ast_app *mixmonapp = NULL;
04172 char *p;
04173 char vars[2048];
04174 int forwardsallowed = 1;
04175 int update_connectedline = 1;
04176 int callcompletedinsl;
04177 struct ao2_iterator memi;
04178 struct ast_datastore *datastore, *transfer_ds;
04179 struct queue_end_bridge *queue_end_bridge = NULL;
04180 const int need_weight = use_weight;
04181
04182 ast_channel_lock(qe->chan);
04183 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
04184 ast_channel_unlock(qe->chan);
04185
04186 memset(&bridge_config, 0, sizeof(bridge_config));
04187 tmpid[0] = 0;
04188 meid[0] = 0;
04189 time(&now);
04190
04191
04192
04193
04194
04195 if (qe->expire && now >= qe->expire) {
04196 res = 0;
04197 goto out;
04198 }
04199
04200 for (; options && *options; options++)
04201 switch (*options) {
04202 case 't':
04203 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
04204 break;
04205 case 'T':
04206 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
04207 break;
04208 case 'w':
04209 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
04210 break;
04211 case 'W':
04212 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
04213 break;
04214 case 'c':
04215 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
04216 break;
04217 case 'd':
04218 nondataquality = 0;
04219 break;
04220 case 'h':
04221 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
04222 break;
04223 case 'H':
04224 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
04225 break;
04226 case 'k':
04227 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
04228 break;
04229 case 'K':
04230 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
04231 break;
04232 case 'n':
04233 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR)
04234 (*tries)++;
04235 else
04236 *tries = qe->parent->membercount;
04237 *noption = 1;
04238 break;
04239 case 'i':
04240 forwardsallowed = 0;
04241 break;
04242 case 'I':
04243 update_connectedline = 0;
04244 break;
04245 case 'x':
04246 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
04247 break;
04248 case 'X':
04249 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
04250 break;
04251 case 'C':
04252 qe->cancel_answered_elsewhere = 1;
04253 break;
04254 }
04255
04256
04257
04258
04259 if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) {
04260 qe->cancel_answered_elsewhere = 1;
04261 }
04262
04263
04264 if (need_weight)
04265 ao2_lock(queues);
04266 ao2_lock(qe->parent);
04267 ast_debug(1, "%s is trying to call a queue member.\n",
04268 qe->chan->name);
04269 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
04270 if (!ast_strlen_zero(qe->announce))
04271 announce = qe->announce;
04272 if (!ast_strlen_zero(announceoverride))
04273 announce = announceoverride;
04274
04275 memi = ao2_iterator_init(qe->parent->members, 0);
04276 while ((cur = ao2_iterator_next(&memi))) {
04277 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
04278 struct ast_dialed_interface *di;
04279 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
04280 if (!tmp) {
04281 ao2_ref(cur, -1);
04282 ao2_unlock(qe->parent);
04283 ao2_iterator_destroy(&memi);
04284 if (need_weight)
04285 ao2_unlock(queues);
04286 goto out;
04287 }
04288 if (!datastore) {
04289 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
04290 ao2_ref(cur, -1);
04291 ao2_unlock(qe->parent);
04292 ao2_iterator_destroy(&memi);
04293 if (need_weight)
04294 ao2_unlock(queues);
04295 callattempt_free(tmp);
04296 goto out;
04297 }
04298 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
04299 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
04300 ao2_ref(cur, -1);
04301 ao2_unlock(&qe->parent);
04302 ao2_iterator_destroy(&memi);
04303 if (need_weight)
04304 ao2_unlock(queues);
04305 callattempt_free(tmp);
04306 goto out;
04307 }
04308 datastore->data = dialed_interfaces;
04309 AST_LIST_HEAD_INIT(dialed_interfaces);
04310
04311 ast_channel_lock(qe->chan);
04312 ast_channel_datastore_add(qe->chan, datastore);
04313 ast_channel_unlock(qe->chan);
04314 } else
04315 dialed_interfaces = datastore->data;
04316
04317 AST_LIST_LOCK(dialed_interfaces);
04318 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
04319 if (!strcasecmp(cur->interface, di->interface)) {
04320 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n",
04321 di->interface);
04322 break;
04323 }
04324 }
04325 AST_LIST_UNLOCK(dialed_interfaces);
04326
04327 if (di) {
04328 callattempt_free(tmp);
04329 continue;
04330 }
04331
04332
04333
04334
04335
04336 if (strncasecmp(cur->interface, "Local/", 6)) {
04337 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
04338 ao2_ref(cur, -1);
04339 ao2_unlock(qe->parent);
04340 ao2_iterator_destroy(&memi);
04341 if (need_weight)
04342 ao2_unlock(queues);
04343 callattempt_free(tmp);
04344 goto out;
04345 }
04346 strcpy(di->interface, cur->interface);
04347
04348 AST_LIST_LOCK(dialed_interfaces);
04349 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
04350 AST_LIST_UNLOCK(dialed_interfaces);
04351 }
04352
04353 ast_channel_lock(qe->chan);
04354
04355
04356
04357
04358
04359
04360 ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
04361 ast_channel_unlock(qe->chan);
04362
04363 tmp->stillgoing = -1;
04364 tmp->member = cur;
04365 tmp->lastcall = cur->lastcall;
04366 tmp->lastqueue = cur->lastqueue;
04367 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
04368
04369
04370 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
04371
04372
04373
04374 tmp->q_next = outgoing;
04375 outgoing = tmp;
04376
04377 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
04378 break;
04379 } else {
04380 callattempt_free(tmp);
04381 }
04382 }
04383 ao2_iterator_destroy(&memi);
04384
04385 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
04386
04387 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
04388 to = (qe->expire - now) * 1000;
04389 else
04390 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
04391 } else {
04392
04393 if (qe->expire && qe->expire<=now) {
04394 to = 0;
04395 } else if (qe->parent->timeout) {
04396 to = qe->parent->timeout * 1000;
04397 } else {
04398 to = -1;
04399 }
04400 }
04401 orig = to;
04402 ++qe->pending;
04403 ao2_unlock(qe->parent);
04404 ring_one(qe, outgoing, &numbusies);
04405 if (need_weight)
04406 ao2_unlock(queues);
04407 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
04408
04409
04410
04411
04412
04413
04414 ast_channel_lock(qe->chan);
04415 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
04416 ast_datastore_free(datastore);
04417 }
04418 ast_channel_unlock(qe->chan);
04419 ao2_lock(qe->parent);
04420 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
04421 store_next_rr(qe, outgoing);
04422 }
04423 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
04424 store_next_lin(qe, outgoing);
04425 }
04426 ao2_unlock(qe->parent);
04427 peer = lpeer ? lpeer->chan : NULL;
04428 if (!peer) {
04429 qe->pending = 0;
04430 if (to) {
04431
04432 res = -1;
04433 } else {
04434
04435 res = digit;
04436 }
04437 if (res == -1)
04438 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
04439 if (ast_cdr_isset_unanswered()) {
04440
04441
04442 struct callattempt *o;
04443 for (o = outgoing; o; o = o->q_next) {
04444 if (!o->chan) {
04445 continue;
04446 }
04447 if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) {
04448 ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED);
04449 break;
04450 }
04451 }
04452 }
04453 } else {
04454
04455
04456
04457 if (!strcmp(qe->chan->tech->type, "DAHDI"))
04458 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04459 if (!strcmp(peer->tech->type, "DAHDI"))
04460 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04461
04462 time(&now);
04463 recalc_holdtime(qe, (now - qe->start));
04464 ao2_lock(qe->parent);
04465 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
04466 ao2_unlock(qe->parent);
04467 member = lpeer->member;
04468
04469 ao2_ref(member, 1);
04470 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
04471 outgoing = NULL;
04472 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
04473 int res2;
04474
04475 res2 = ast_autoservice_start(qe->chan);
04476 if (!res2) {
04477 if (qe->parent->memberdelay) {
04478 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
04479 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
04480 }
04481 if (!res2 && announce) {
04482 play_file(peer, announce);
04483 }
04484 if (!res2 && qe->parent->reportholdtime) {
04485 if (!play_file(peer, qe->parent->sound_reporthold)) {
04486 int holdtime, holdtimesecs;
04487
04488 time(&now);
04489 holdtime = abs((now - qe->start) / 60);
04490 holdtimesecs = abs((now - qe->start) % 60);
04491 if (holdtime > 0) {
04492 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
04493 play_file(peer, qe->parent->sound_minutes);
04494 }
04495 if (holdtimesecs > 1) {
04496 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
04497 play_file(peer, qe->parent->sound_seconds);
04498 }
04499 }
04500 }
04501 }
04502 res2 |= ast_autoservice_stop(qe->chan);
04503 if (ast_check_hangup(peer)) {
04504
04505 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
04506 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
04507 if (qe->parent->eventwhencalled)
04508 manager_event(EVENT_FLAG_AGENT, "AgentDump",
04509 "Queue: %s\r\n"
04510 "Uniqueid: %s\r\n"
04511 "Channel: %s\r\n"
04512 "Member: %s\r\n"
04513 "MemberName: %s\r\n"
04514 "%s",
04515 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04516 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
04517 ast_hangup(peer);
04518 ao2_ref(member, -1);
04519 goto out;
04520 } else if (res2) {
04521
04522 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
04523 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
04524 record_abandoned(qe);
04525 ast_hangup(peer);
04526 ao2_ref(member, -1);
04527 return -1;
04528 }
04529 }
04530
04531 if (ringing)
04532 ast_indicate(qe->chan,-1);
04533 else
04534 ast_moh_stop(qe->chan);
04535
04536 if (qe->chan->cdr)
04537 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
04538
04539 res = ast_channel_make_compatible(qe->chan, peer);
04540 if (res < 0) {
04541 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
04542 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
04543 record_abandoned(qe);
04544 ast_cdr_failed(qe->chan->cdr);
04545 ast_hangup(peer);
04546 ao2_ref(member, -1);
04547 return -1;
04548 }
04549
04550
04551 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
04552 if (play_file(qe->chan, qe->parent->sound_callerannounce))
04553 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
04554 }
04555
04556 ao2_lock(qe->parent);
04557
04558
04559 if (qe->parent->setinterfacevar) {
04560 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
04561 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
04562 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04563 pbx_builtin_setvar_multiple(peer, interfacevar);
04564 }
04565
04566
04567
04568 if (qe->parent->setqueueentryvar) {
04569 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
04570 (long) time(NULL) - qe->start, qe->opos);
04571 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04572 pbx_builtin_setvar_multiple(peer, interfacevar);
04573 }
04574
04575 ao2_unlock(qe->parent);
04576
04577
04578 set_queue_variables(qe->parent, qe->chan);
04579 set_queue_variables(qe->parent, peer);
04580
04581 ast_channel_lock(qe->chan);
04582 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
04583 monitorfilename = ast_strdupa(monitorfilename);
04584 }
04585 ast_channel_unlock(qe->chan);
04586
04587 if (qe->parent->monfmt && *qe->parent->monfmt) {
04588 if (!qe->parent->montype) {
04589 const char *monexec, *monargs;
04590 ast_debug(1, "Starting Monitor as requested.\n");
04591 ast_channel_lock(qe->chan);
04592 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) {
04593 which = qe->chan;
04594 monexec = monexec ? ast_strdupa(monexec) : NULL;
04595 }
04596 else
04597 which = peer;
04598 ast_channel_unlock(qe->chan);
04599 if (monitorfilename) {
04600 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
04601 } else if (qe->chan->cdr) {
04602 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
04603 } else {
04604
04605 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04606 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
04607 }
04608 if (!ast_strlen_zero(monexec)) {
04609 ast_monitor_setjoinfiles(which, 1);
04610 }
04611 } else {
04612 mixmonapp = pbx_findapp("MixMonitor");
04613
04614 if (mixmonapp) {
04615 ast_debug(1, "Starting MixMonitor as requested.\n");
04616 if (!monitorfilename) {
04617 if (qe->chan->cdr)
04618 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
04619 else
04620 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04621 } else {
04622 const char *m = monitorfilename;
04623 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
04624 switch (*m) {
04625 case '^':
04626 if (*(m + 1) == '{')
04627 *p = '$';
04628 break;
04629 case ',':
04630 *p++ = '\\';
04631
04632 default:
04633 *p = *m;
04634 }
04635 if (*m == '\0')
04636 break;
04637 }
04638 if (p == tmpid2 + sizeof(tmpid2))
04639 tmpid2[sizeof(tmpid2) - 1] = '\0';
04640
04641 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
04642 }
04643
04644 ast_channel_lock(qe->chan);
04645 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
04646 monitor_exec = ast_strdupa(monitor_exec);
04647 }
04648 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
04649 monitor_options = ast_strdupa(monitor_options);
04650 } else {
04651 monitor_options = "";
04652 }
04653 ast_channel_unlock(qe->chan);
04654
04655 if (monitor_exec) {
04656 const char *m = monitor_exec;
04657 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
04658 switch (*m) {
04659 case '^':
04660 if (*(m + 1) == '{')
04661 *p = '$';
04662 break;
04663 case ',':
04664 *p++ = '\\';
04665
04666 default:
04667 *p = *m;
04668 }
04669 if (*m == '\0')
04670 break;
04671 }
04672 if (p == meid2 + sizeof(meid2))
04673 meid2[sizeof(meid2) - 1] = '\0';
04674
04675 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
04676 }
04677
04678 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
04679
04680 if (!ast_strlen_zero(monitor_exec))
04681 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
04682 else
04683 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
04684
04685 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
04686
04687 if (qe->chan->cdr)
04688 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04689 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
04690 if (qe->chan->cdr)
04691 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04692
04693 } else {
04694 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
04695 }
04696 }
04697 }
04698
04699 leave_queue(qe);
04700 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
04701 ast_debug(1, "app_queue: sendurl=%s.\n", url);
04702 ast_channel_sendurl(peer, url);
04703 }
04704
04705
04706
04707 if (!ast_strlen_zero(macro)) {
04708 macroexec = ast_strdupa(macro);
04709 } else {
04710 if (qe->parent->membermacro)
04711 macroexec = ast_strdupa(qe->parent->membermacro);
04712 }
04713
04714 if (!ast_strlen_zero(macroexec)) {
04715 ast_debug(1, "app_queue: macro=%s.\n", macroexec);
04716
04717 res = ast_autoservice_start(qe->chan);
04718 if (res) {
04719 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04720 res = -1;
04721 }
04722
04723 application = pbx_findapp("Macro");
04724
04725 if (application) {
04726 res = pbx_exec(peer, application, macroexec);
04727 ast_debug(1, "Macro exited with status %d\n", res);
04728 res = 0;
04729 } else {
04730 ast_log(LOG_ERROR, "Could not find application Macro\n");
04731 res = -1;
04732 }
04733
04734 if (ast_autoservice_stop(qe->chan) < 0) {
04735 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04736 res = -1;
04737 }
04738 }
04739
04740
04741
04742 if (!ast_strlen_zero(gosub)) {
04743 gosubexec = ast_strdupa(gosub);
04744 } else {
04745 if (qe->parent->membergosub)
04746 gosubexec = ast_strdupa(qe->parent->membergosub);
04747 }
04748
04749 if (!ast_strlen_zero(gosubexec)) {
04750 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
04751
04752 res = ast_autoservice_start(qe->chan);
04753 if (res) {
04754 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04755 res = -1;
04756 }
04757
04758 application = pbx_findapp("Gosub");
04759
04760 if (application) {
04761 char *gosub_args, *gosub_argstart;
04762
04763
04764 ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context));
04765 ast_copy_string(peer->exten, "s", sizeof(peer->exten));
04766 peer->priority = 0;
04767
04768 gosub_argstart = strchr(gosubexec, ',');
04769 if (gosub_argstart) {
04770 *gosub_argstart = 0;
04771 if (asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1) < 0) {
04772 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
04773 gosub_args = NULL;
04774 }
04775 *gosub_argstart = ',';
04776 } else {
04777 if (asprintf(&gosub_args, "%s,s,1", gosubexec) < 0) {
04778 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
04779 gosub_args = NULL;
04780 }
04781 }
04782 if (gosub_args) {
04783 res = pbx_exec(peer, application, gosub_args);
04784 if (!res) {
04785 struct ast_pbx_args args;
04786 memset(&args, 0, sizeof(args));
04787 args.no_hangup_chan = 1;
04788 ast_pbx_run_args(peer, &args);
04789 }
04790 ast_free(gosub_args);
04791 ast_debug(1, "Gosub exited with status %d\n", res);
04792 } else {
04793 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
04794 }
04795 } else {
04796 ast_log(LOG_ERROR, "Could not find application Gosub\n");
04797 res = -1;
04798 }
04799
04800 if (ast_autoservice_stop(qe->chan) < 0) {
04801 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04802 res = -1;
04803 }
04804 }
04805
04806 if (!ast_strlen_zero(agi)) {
04807 ast_debug(1, "app_queue: agi=%s.\n", agi);
04808 application = pbx_findapp("agi");
04809 if (application) {
04810 agiexec = ast_strdupa(agi);
04811 ret = pbx_exec(qe->chan, application, agiexec);
04812 } else
04813 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
04814 }
04815 qe->handled++;
04816 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
04817 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
04818 if (update_cdr && qe->chan->cdr)
04819 ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel));
04820 if (qe->parent->eventwhencalled)
04821 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
04822 "Queue: %s\r\n"
04823 "Uniqueid: %s\r\n"
04824 "Channel: %s\r\n"
04825 "Member: %s\r\n"
04826 "MemberName: %s\r\n"
04827 "Holdtime: %ld\r\n"
04828 "BridgedChannel: %s\r\n"
04829 "Ringtime: %ld\r\n"
04830 "%s",
04831 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04832 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
04833 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
04834 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
04835 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
04836
04837 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
04838 queue_end_bridge->q = qe->parent;
04839 queue_end_bridge->chan = qe->chan;
04840 bridge_config.end_bridge_callback = end_bridge_callback;
04841 bridge_config.end_bridge_callback_data = queue_end_bridge;
04842 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
04843
04844
04845
04846
04847 queue_t_ref(qe->parent, "For bridge_config reference");
04848 }
04849
04850 time(&callstart);
04851 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
04852 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
04853
04854
04855
04856
04857
04858 ast_channel_lock(qe->chan);
04859 if (!attended_transfer_occurred(qe->chan)) {
04860 struct ast_datastore *tds;
04861
04862
04863 if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) {
04864 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
04865 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
04866 (long) (time(NULL) - callstart), qe->opos);
04867 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
04868 } else if (ast_check_hangup(qe->chan)) {
04869 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
04870 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
04871 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
04872 } else {
04873 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
04874 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
04875 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
04876 }
04877 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
04878 ast_channel_datastore_remove(qe->chan, tds);
04879 }
04880 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
04881 } else {
04882
04883 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
04884 }
04885
04886 if (transfer_ds) {
04887 ast_datastore_free(transfer_ds);
04888 }
04889 ast_channel_unlock(qe->chan);
04890 ast_hangup(peer);
04891 res = bridge ? bridge : 1;
04892 ao2_ref(member, -1);
04893 }
04894 out:
04895 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
04896
04897 return res;
04898 }
04899
04900 static int wait_a_bit(struct queue_ent *qe)
04901 {
04902
04903 int retrywait = qe->parent->retry * 1000;
04904
04905 int res = ast_waitfordigit(qe->chan, retrywait);
04906 if (res > 0 && !valid_exit(qe, res))
04907 res = 0;
04908
04909 return res;
04910 }
04911
04912 static struct member *interface_exists(struct call_queue *q, const char *interface)
04913 {
04914 struct member *mem;
04915 struct ao2_iterator mem_iter;
04916
04917 if (!q)
04918 return NULL;
04919
04920 mem_iter = ao2_iterator_init(q->members, 0);
04921 while ((mem = ao2_iterator_next(&mem_iter))) {
04922 if (!strcasecmp(interface, mem->interface)) {
04923 ao2_iterator_destroy(&mem_iter);
04924 return mem;
04925 }
04926 ao2_ref(mem, -1);
04927 }
04928 ao2_iterator_destroy(&mem_iter);
04929
04930 return NULL;
04931 }
04932
04933
04934
04935
04936
04937
04938 static void dump_queue_members(struct call_queue *pm_queue)
04939 {
04940 struct member *cur_member;
04941 char value[PM_MAX_LEN];
04942 int value_len = 0;
04943 int res;
04944 struct ao2_iterator mem_iter;
04945
04946 memset(value, 0, sizeof(value));
04947
04948 if (!pm_queue)
04949 return;
04950
04951 mem_iter = ao2_iterator_init(pm_queue->members, 0);
04952 while ((cur_member = ao2_iterator_next(&mem_iter))) {
04953 if (!cur_member->dynamic) {
04954 ao2_ref(cur_member, -1);
04955 continue;
04956 }
04957
04958 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
04959 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
04960
04961 ao2_ref(cur_member, -1);
04962
04963 if (res != strlen(value + value_len)) {
04964 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
04965 break;
04966 }
04967 value_len += res;
04968 }
04969 ao2_iterator_destroy(&mem_iter);
04970
04971 if (value_len && !cur_member) {
04972 if (ast_db_put(pm_family, pm_queue->name, value))
04973 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
04974 } else
04975
04976 ast_db_del(pm_family, pm_queue->name);
04977 }
04978
04979
04980
04981
04982
04983
04984
04985 static int remove_from_queue(const char *queuename, const char *interface)
04986 {
04987 struct call_queue *q, tmpq = {
04988 .name = queuename,
04989 };
04990 struct member *mem, tmpmem;
04991 int res = RES_NOSUCHQUEUE;
04992
04993 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04994 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
04995 ao2_lock(queues);
04996 ao2_lock(q);
04997 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
04998
04999 if (!mem->dynamic) {
05000 ao2_ref(mem, -1);
05001 ao2_unlock(q);
05002 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
05003 ao2_unlock(queues);
05004 return RES_NOT_DYNAMIC;
05005 }
05006 q->membercount--;
05007 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
05008 "Queue: %s\r\n"
05009 "Location: %s\r\n"
05010 "MemberName: %s\r\n",
05011 q->name, mem->interface, mem->membername);
05012 ao2_unlink(q->members, mem);
05013 ao2_ref(mem, -1);
05014
05015 if (queue_persistent_members)
05016 dump_queue_members(q);
05017
05018 res = RES_OKAY;
05019 } else {
05020 res = RES_EXISTS;
05021 }
05022 ao2_unlock(q);
05023 ao2_unlock(queues);
05024 queue_t_unref(q, "Expiring temporary reference");
05025 }
05026
05027 return res;
05028 }
05029
05030
05031
05032
05033
05034
05035
05036
05037 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
05038 {
05039 struct call_queue *q;
05040 struct member *new_member, *old_member;
05041 int res = RES_NOSUCHQUEUE;
05042
05043
05044
05045 if (!(q = load_realtime_queue(queuename)))
05046 return res;
05047
05048 ao2_lock(queues);
05049
05050 ao2_lock(q);
05051 if ((old_member = interface_exists(q, interface)) == NULL) {
05052 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
05053 new_member->dynamic = 1;
05054 ao2_link(q->members, new_member);
05055 q->membercount++;
05056 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
05057 "Queue: %s\r\n"
05058 "Location: %s\r\n"
05059 "MemberName: %s\r\n"
05060 "Membership: %s\r\n"
05061 "Penalty: %d\r\n"
05062 "CallsTaken: %d\r\n"
05063 "LastCall: %d\r\n"
05064 "Status: %d\r\n"
05065 "Paused: %d\r\n",
05066 q->name, new_member->interface, new_member->membername,
05067 "dynamic",
05068 new_member->penalty, new_member->calls, (int) new_member->lastcall,
05069 new_member->status, new_member->paused);
05070
05071 ao2_ref(new_member, -1);
05072 new_member = NULL;
05073
05074 if (dump)
05075 dump_queue_members(q);
05076
05077 res = RES_OKAY;
05078 } else {
05079 res = RES_OUTOFMEMORY;
05080 }
05081 } else {
05082 ao2_ref(old_member, -1);
05083 res = RES_EXISTS;
05084 }
05085 ao2_unlock(q);
05086 ao2_unlock(queues);
05087 queue_t_unref(q, "Expiring temporary reference");
05088
05089 return res;
05090 }
05091
05092 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
05093 {
05094 int found = 0;
05095 struct call_queue *q;
05096 struct member *mem;
05097 struct ao2_iterator queue_iter;
05098 int failed;
05099
05100
05101
05102 if (ast_strlen_zero(queuename))
05103 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
05104
05105 queue_iter = ao2_iterator_init(queues, 0);
05106 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
05107 ao2_lock(q);
05108 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05109 if ((mem = interface_exists(q, interface))) {
05110 if (mem->paused == paused) {
05111 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
05112 }
05113
05114 failed = 0;
05115 if (mem->realtime) {
05116 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
05117 }
05118
05119 if (failed) {
05120 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
05121 ao2_ref(mem, -1);
05122 ao2_unlock(q);
05123 queue_t_unref(q, "Done with iterator");
05124 continue;
05125 }
05126 found++;
05127 mem->paused = paused;
05128
05129 if (queue_persistent_members)
05130 dump_queue_members(q);
05131
05132 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
05133
05134 if (!ast_strlen_zero(reason)) {
05135 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05136 "Queue: %s\r\n"
05137 "Location: %s\r\n"
05138 "MemberName: %s\r\n"
05139 "Paused: %d\r\n"
05140 "Reason: %s\r\n",
05141 q->name, mem->interface, mem->membername, paused, reason);
05142 } else {
05143 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05144 "Queue: %s\r\n"
05145 "Location: %s\r\n"
05146 "MemberName: %s\r\n"
05147 "Paused: %d\r\n",
05148 q->name, mem->interface, mem->membername, paused);
05149 }
05150 ao2_ref(mem, -1);
05151 }
05152 }
05153
05154 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
05155 ao2_unlock(q);
05156 queue_t_unref(q, "Done with iterator");
05157 break;
05158 }
05159
05160 ao2_unlock(q);
05161 queue_t_unref(q, "Done with iterator");
05162 }
05163 ao2_iterator_destroy(&queue_iter);
05164
05165 return found ? RESULT_SUCCESS : RESULT_FAILURE;
05166 }
05167
05168
05169 static int set_member_penalty(const char *queuename, const char *interface, int penalty)
05170 {
05171 int foundinterface = 0, foundqueue = 0;
05172 struct call_queue *q;
05173 struct member *mem;
05174 struct ao2_iterator queue_iter;
05175
05176 if (penalty < 0) {
05177 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
05178 return RESULT_FAILURE;
05179 }
05180
05181 queue_iter = ao2_iterator_init(queues, 0);
05182 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
05183 ao2_lock(q);
05184 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05185 foundqueue++;
05186 if ((mem = interface_exists(q, interface))) {
05187 foundinterface++;
05188 mem->penalty = penalty;
05189
05190 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
05191 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
05192 "Queue: %s\r\n"
05193 "Location: %s\r\n"
05194 "Penalty: %d\r\n",
05195 q->name, mem->interface, penalty);
05196 ao2_ref(mem, -1);
05197 }
05198 }
05199 ao2_unlock(q);
05200 queue_t_unref(q, "Done with iterator");
05201 }
05202 ao2_iterator_destroy(&queue_iter);
05203
05204 if (foundinterface) {
05205 return RESULT_SUCCESS;
05206 } else if (!foundqueue) {
05207 ast_log (LOG_ERROR, "Invalid queuename\n");
05208 } else {
05209 ast_log (LOG_ERROR, "Invalid interface\n");
05210 }
05211
05212 return RESULT_FAILURE;
05213 }
05214
05215
05216
05217
05218 static int get_member_penalty(char *queuename, char *interface)
05219 {
05220 int foundqueue = 0, penalty;
05221 struct call_queue *q, tmpq = {
05222 .name = queuename,
05223 };
05224 struct member *mem;
05225
05226 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
05227 foundqueue = 1;
05228 ao2_lock(q);
05229 if ((mem = interface_exists(q, interface))) {
05230 penalty = mem->penalty;
05231 ao2_ref(mem, -1);
05232 ao2_unlock(q);
05233 queue_t_unref(q, "Search complete");
05234 return penalty;
05235 }
05236 ao2_unlock(q);
05237 queue_t_unref(q, "Search complete");
05238 }
05239
05240
05241 if (foundqueue)
05242 ast_log (LOG_ERROR, "Invalid queuename\n");
05243 else
05244 ast_log (LOG_ERROR, "Invalid interface\n");
05245
05246 return RESULT_FAILURE;
05247 }
05248
05249
05250 static void reload_queue_members(void)
05251 {
05252 char *cur_ptr;
05253 const char *queue_name;
05254 char *member;
05255 char *interface;
05256 char *membername = NULL;
05257 char *state_interface;
05258 char *penalty_tok;
05259 int penalty = 0;
05260 char *paused_tok;
05261 int paused = 0;
05262 struct ast_db_entry *db_tree;
05263 struct ast_db_entry *entry;
05264 struct call_queue *cur_queue;
05265 char queue_data[PM_MAX_LEN];
05266
05267 ao2_lock(queues);
05268
05269
05270 db_tree = ast_db_gettree(pm_family, NULL);
05271 for (entry = db_tree; entry; entry = entry->next) {
05272
05273 queue_name = entry->key + strlen(pm_family) + 2;
05274
05275 {
05276 struct call_queue tmpq = {
05277 .name = queue_name,
05278 };
05279 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
05280 }
05281
05282 if (!cur_queue)
05283 cur_queue = load_realtime_queue(queue_name);
05284
05285 if (!cur_queue) {
05286
05287
05288 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
05289 ast_db_del(pm_family, queue_name);
05290 continue;
05291 }
05292
05293 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
05294 queue_t_unref(cur_queue, "Expire reload reference");
05295 continue;
05296 }
05297
05298 cur_ptr = queue_data;
05299 while ((member = strsep(&cur_ptr, ",|"))) {
05300 if (ast_strlen_zero(member))
05301 continue;
05302
05303 interface = strsep(&member, ";");
05304 penalty_tok = strsep(&member, ";");
05305 paused_tok = strsep(&member, ";");
05306 membername = strsep(&member, ";");
05307 state_interface = strsep(&member, ";");
05308
05309 if (!penalty_tok) {
05310 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
05311 break;
05312 }
05313 penalty = strtol(penalty_tok, NULL, 10);
05314 if (errno == ERANGE) {
05315 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
05316 break;
05317 }
05318
05319 if (!paused_tok) {
05320 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
05321 break;
05322 }
05323 paused = strtol(paused_tok, NULL, 10);
05324 if ((errno == ERANGE) || paused < 0 || paused > 1) {
05325 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
05326 break;
05327 }
05328
05329 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
05330
05331 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
05332 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
05333 break;
05334 }
05335 }
05336 queue_t_unref(cur_queue, "Expire reload reference");
05337 }
05338
05339 ao2_unlock(queues);
05340 if (db_tree) {
05341 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
05342 ast_db_freetree(db_tree);
05343 }
05344 }
05345
05346
05347 static int pqm_exec(struct ast_channel *chan, const char *data)
05348 {
05349 char *parse;
05350 AST_DECLARE_APP_ARGS(args,
05351 AST_APP_ARG(queuename);
05352 AST_APP_ARG(interface);
05353 AST_APP_ARG(options);
05354 AST_APP_ARG(reason);
05355 );
05356
05357 if (ast_strlen_zero(data)) {
05358 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
05359 return -1;
05360 }
05361
05362 parse = ast_strdupa(data);
05363
05364 AST_STANDARD_APP_ARGS(args, parse);
05365
05366 if (ast_strlen_zero(args.interface)) {
05367 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05368 return -1;
05369 }
05370
05371 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
05372 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
05373 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
05374 return 0;
05375 }
05376
05377 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
05378
05379 return 0;
05380 }
05381
05382
05383 static int upqm_exec(struct ast_channel *chan, const char *data)
05384 {
05385 char *parse;
05386 AST_DECLARE_APP_ARGS(args,
05387 AST_APP_ARG(queuename);
05388 AST_APP_ARG(interface);
05389 AST_APP_ARG(options);
05390 AST_APP_ARG(reason);
05391 );
05392
05393 if (ast_strlen_zero(data)) {
05394 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
05395 return -1;
05396 }
05397
05398 parse = ast_strdupa(data);
05399
05400 AST_STANDARD_APP_ARGS(args, parse);
05401
05402 if (ast_strlen_zero(args.interface)) {
05403 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05404 return -1;
05405 }
05406
05407 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
05408 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
05409 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
05410 return 0;
05411 }
05412
05413 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
05414
05415 return 0;
05416 }
05417
05418
05419 static int rqm_exec(struct ast_channel *chan, const char *data)
05420 {
05421 int res=-1;
05422 char *parse, *temppos = NULL;
05423 AST_DECLARE_APP_ARGS(args,
05424 AST_APP_ARG(queuename);
05425 AST_APP_ARG(interface);
05426 AST_APP_ARG(options);
05427 );
05428
05429
05430 if (ast_strlen_zero(data)) {
05431 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n");
05432 return -1;
05433 }
05434
05435 parse = ast_strdupa(data);
05436
05437 AST_STANDARD_APP_ARGS(args, parse);
05438
05439 if (ast_strlen_zero(args.interface)) {
05440 args.interface = ast_strdupa(chan->name);
05441 temppos = strrchr(args.interface, '-');
05442 if (temppos)
05443 *temppos = '\0';
05444 }
05445
05446 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
05447
05448 switch (remove_from_queue(args.queuename, args.interface)) {
05449 case RES_OKAY:
05450 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
05451 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
05452 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
05453 res = 0;
05454 break;
05455 case RES_EXISTS:
05456 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
05457 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
05458 res = 0;
05459 break;
05460 case RES_NOSUCHQUEUE:
05461 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
05462 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
05463 res = 0;
05464 break;
05465 case RES_NOT_DYNAMIC:
05466 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
05467 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
05468 res = 0;
05469 break;
05470 }
05471
05472 return res;
05473 }
05474
05475
05476 static int aqm_exec(struct ast_channel *chan, const char *data)
05477 {
05478 int res=-1;
05479 char *parse, *temppos = NULL;
05480 AST_DECLARE_APP_ARGS(args,
05481 AST_APP_ARG(queuename);
05482 AST_APP_ARG(interface);
05483 AST_APP_ARG(penalty);
05484 AST_APP_ARG(options);
05485 AST_APP_ARG(membername);
05486 AST_APP_ARG(state_interface);
05487 );
05488 int penalty = 0;
05489
05490 if (ast_strlen_zero(data)) {
05491 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
05492 return -1;
05493 }
05494
05495 parse = ast_strdupa(data);
05496
05497 AST_STANDARD_APP_ARGS(args, parse);
05498
05499 if (ast_strlen_zero(args.interface)) {
05500 args.interface = ast_strdupa(chan->name);
05501 temppos = strrchr(args.interface, '-');
05502 if (temppos)
05503 *temppos = '\0';
05504 }
05505
05506 if (!ast_strlen_zero(args.penalty)) {
05507 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
05508 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
05509 penalty = 0;
05510 }
05511 }
05512
05513 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
05514 case RES_OKAY:
05515 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
05516 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
05517 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
05518 res = 0;
05519 break;
05520 case RES_EXISTS:
05521 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
05522 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
05523 res = 0;
05524 break;
05525 case RES_NOSUCHQUEUE:
05526 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
05527 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
05528 res = 0;
05529 break;
05530 case RES_OUTOFMEMORY:
05531 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
05532 break;
05533 }
05534
05535 return res;
05536 }
05537
05538
05539 static int ql_exec(struct ast_channel *chan, const char *data)
05540 {
05541 char *parse;
05542
05543 AST_DECLARE_APP_ARGS(args,
05544 AST_APP_ARG(queuename);
05545 AST_APP_ARG(uniqueid);
05546 AST_APP_ARG(membername);
05547 AST_APP_ARG(event);
05548 AST_APP_ARG(params);
05549 );
05550
05551 if (ast_strlen_zero(data)) {
05552 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
05553 return -1;
05554 }
05555
05556 parse = ast_strdupa(data);
05557
05558 AST_STANDARD_APP_ARGS(args, parse);
05559
05560 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
05561 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
05562 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
05563 return -1;
05564 }
05565
05566 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
05567 "%s", args.params ? args.params : "");
05568
05569 return 0;
05570 }
05571
05572
05573 static void copy_rules(struct queue_ent *qe, const char *rulename)
05574 {
05575 struct penalty_rule *pr_iter;
05576 struct rule_list *rl_iter;
05577 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
05578 AST_LIST_LOCK(&rule_lists);
05579 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
05580 if (!strcasecmp(rl_iter->name, tmp))
05581 break;
05582 }
05583 if (rl_iter) {
05584 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
05585 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
05586 if (!new_pr) {
05587 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
05588 AST_LIST_UNLOCK(&rule_lists);
05589 break;
05590 }
05591 new_pr->time = pr_iter->time;
05592 new_pr->max_value = pr_iter->max_value;
05593 new_pr->min_value = pr_iter->min_value;
05594 new_pr->max_relative = pr_iter->max_relative;
05595 new_pr->min_relative = pr_iter->min_relative;
05596 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
05597 }
05598 }
05599 AST_LIST_UNLOCK(&rule_lists);
05600 }
05601
05602
05603
05604
05605
05606
05607
05608
05609
05610
05611
05612
05613
05614 static int queue_exec(struct ast_channel *chan, const char *data)
05615 {
05616 int res=-1;
05617 int ringing=0;
05618 const char *user_priority;
05619 const char *max_penalty_str;
05620 const char *min_penalty_str;
05621 int prio;
05622 int qcontinue = 0;
05623 int max_penalty, min_penalty;
05624 enum queue_result reason = QUEUE_UNKNOWN;
05625
05626 int tries = 0;
05627 int noption = 0;
05628 char *parse;
05629 int makeannouncement = 0;
05630 int position = 0;
05631 AST_DECLARE_APP_ARGS(args,
05632 AST_APP_ARG(queuename);
05633 AST_APP_ARG(options);
05634 AST_APP_ARG(url);
05635 AST_APP_ARG(announceoverride);
05636 AST_APP_ARG(queuetimeoutstr);
05637 AST_APP_ARG(agi);
05638 AST_APP_ARG(macro);
05639 AST_APP_ARG(gosub);
05640 AST_APP_ARG(rule);
05641 AST_APP_ARG(position);
05642 );
05643
05644 struct queue_ent qe = { 0 };
05645
05646 if (ast_strlen_zero(data)) {
05647 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
05648 return -1;
05649 }
05650
05651 parse = ast_strdupa(data);
05652 AST_STANDARD_APP_ARGS(args, parse);
05653
05654
05655 qe.start = time(NULL);
05656
05657
05658 if (!ast_strlen_zero(args.queuetimeoutstr))
05659 qe.expire = qe.start + atoi(args.queuetimeoutstr);
05660 else
05661 qe.expire = 0;
05662
05663
05664 ast_channel_lock(chan);
05665 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
05666 if (user_priority) {
05667 if (sscanf(user_priority, "%30d", &prio) == 1) {
05668 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
05669 } else {
05670 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
05671 user_priority, chan->name);
05672 prio = 0;
05673 }
05674 } else {
05675 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
05676 prio = 0;
05677 }
05678
05679
05680
05681 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
05682 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
05683 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
05684 } else {
05685 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
05686 max_penalty_str, chan->name);
05687 max_penalty = 0;
05688 }
05689 } else {
05690 max_penalty = 0;
05691 }
05692
05693 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
05694 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
05695 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
05696 } else {
05697 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
05698 min_penalty_str, chan->name);
05699 min_penalty = 0;
05700 }
05701 } else {
05702 min_penalty = 0;
05703 }
05704 ast_channel_unlock(chan);
05705
05706 if (args.options && (strchr(args.options, 'r')))
05707 ringing = 1;
05708
05709 if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
05710 qe.ring_when_ringing = 1;
05711 }
05712
05713 if (args.options && (strchr(args.options, 'c')))
05714 qcontinue = 1;
05715
05716 if (args.position) {
05717 position = atoi(args.position);
05718 if (position < 0) {
05719 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
05720 position = 0;
05721 }
05722 }
05723
05724 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
05725 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
05726
05727 qe.chan = chan;
05728 qe.prio = prio;
05729 qe.max_penalty = max_penalty;
05730 qe.min_penalty = min_penalty;
05731 qe.last_pos_said = 0;
05732 qe.last_pos = 0;
05733 qe.last_periodic_announce_time = time(NULL);
05734 qe.last_periodic_announce_sound = 0;
05735 qe.valid_digits = 0;
05736 if (join_queue(args.queuename, &qe, &reason, position)) {
05737 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
05738 set_queue_result(chan, reason);
05739 return 0;
05740 }
05741 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d",
05742 S_OR(args.url, ""),
05743 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
05744 qe.opos);
05745 copy_rules(&qe, args.rule);
05746 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
05747 check_turns:
05748 if (ringing) {
05749 ast_indicate(chan, AST_CONTROL_RINGING);
05750 } else {
05751 ast_moh_start(chan, qe.moh, NULL);
05752 }
05753
05754
05755 res = wait_our_turn(&qe, ringing, &reason);
05756 if (res) {
05757 goto stop;
05758 }
05759
05760 makeannouncement = 0;
05761
05762 for (;;) {
05763
05764
05765
05766
05767
05768
05769 if (qe.expire && (time(NULL) >= qe.expire)) {
05770 record_abandoned(&qe);
05771 reason = QUEUE_TIMEOUT;
05772 res = 0;
05773 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
05774 qe.pos, qe.opos, (long) time(NULL) - qe.start);
05775 break;
05776 }
05777
05778 if (makeannouncement) {
05779
05780 if (qe.parent->announcefrequency)
05781 if ((res = say_position(&qe,ringing)))
05782 goto stop;
05783 }
05784 makeannouncement = 1;
05785
05786
05787 if (qe.parent->periodicannouncefrequency)
05788 if ((res = say_periodic_announcement(&qe,ringing)))
05789 goto stop;
05790
05791
05792 if (qe.expire && (time(NULL) >= qe.expire)) {
05793 record_abandoned(&qe);
05794 reason = QUEUE_TIMEOUT;
05795 res = 0;
05796 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05797 break;
05798 }
05799
05800
05801 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
05802 update_qe_rule(&qe);
05803 }
05804
05805
05806 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
05807 if (res) {
05808 goto stop;
05809 }
05810
05811 if (qe.parent->leavewhenempty) {
05812 int status = 0;
05813 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
05814 record_abandoned(&qe);
05815 reason = QUEUE_LEAVEEMPTY;
05816 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
05817 res = 0;
05818 break;
05819 }
05820 }
05821
05822
05823 if (noption && tries >= qe.parent->membercount) {
05824 ast_verb(3, "Exiting on time-out cycle\n");
05825 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05826 record_abandoned(&qe);
05827 reason = QUEUE_TIMEOUT;
05828 res = 0;
05829 break;
05830 }
05831
05832
05833
05834 if (qe.expire && (time(NULL) >= qe.expire)) {
05835 record_abandoned(&qe);
05836 reason = QUEUE_TIMEOUT;
05837 res = 0;
05838 ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
05839 break;
05840 }
05841
05842
05843 update_realtime_members(qe.parent);
05844
05845 res = wait_a_bit(&qe);
05846 if (res)
05847 goto stop;
05848
05849
05850
05851
05852
05853 if (!is_our_turn(&qe)) {
05854 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
05855 goto check_turns;
05856 }
05857 }
05858
05859 stop:
05860 if (res) {
05861 if (res < 0) {
05862 if (!qe.handled) {
05863 record_abandoned(&qe);
05864 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
05865 "%d|%d|%ld", qe.pos, qe.opos,
05866 (long) time(NULL) - qe.start);
05867 res = -1;
05868 } else if (qcontinue) {
05869 reason = QUEUE_CONTINUE;
05870 res = 0;
05871 }
05872 } else if (qe.valid_digits) {
05873 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
05874 "%s|%d", qe.digits, qe.pos);
05875 }
05876 }
05877
05878
05879 if (res >= 0) {
05880 res = 0;
05881 if (ringing) {
05882 ast_indicate(chan, -1);
05883 } else {
05884 ast_moh_stop(chan);
05885 }
05886 ast_stopstream(chan);
05887 }
05888
05889 set_queue_variables(qe.parent, qe.chan);
05890
05891 leave_queue(&qe);
05892 if (reason != QUEUE_UNKNOWN)
05893 set_queue_result(chan, reason);
05894
05895 if (qe.parent) {
05896
05897
05898
05899 qe.parent = queue_unref(qe.parent);
05900 }
05901
05902 return res;
05903 }
05904
05905
05906
05907
05908
05909
05910 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
05911 {
05912 int res = -1;
05913 struct call_queue *q, tmpq = {
05914 .name = data,
05915 };
05916
05917 char interfacevar[256] = "";
05918 float sl = 0;
05919
05920 if (ast_strlen_zero(data)) {
05921 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05922 return -1;
05923 }
05924
05925 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
05926 ao2_lock(q);
05927 if (q->setqueuevar) {
05928 sl = 0;
05929 res = 0;
05930
05931 if (q->callscompleted > 0) {
05932 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
05933 }
05934
05935 snprintf(interfacevar, sizeof(interfacevar),
05936 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
05937 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
05938
05939 pbx_builtin_setvar_multiple(chan, interfacevar);
05940 }
05941
05942 ao2_unlock(q);
05943 queue_t_unref(q, "Done with QUEUE() function");
05944 } else {
05945 ast_log(LOG_WARNING, "queue %s was not found\n", data);
05946 }
05947
05948 snprintf(buf, len, "%d", res);
05949
05950 return 0;
05951 }
05952
05953
05954
05955
05956
05957 static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
05958 {
05959 struct call_queue *q;
05960
05961 buf[0] = '\0';
05962
05963 if (ast_strlen_zero(data)) {
05964 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05965 return -1;
05966 }
05967 q = load_realtime_queue(data);
05968 snprintf(buf, len, "%d", q != NULL? 1 : 0);
05969 if (q) {
05970 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
05971 }
05972
05973 return 0;
05974 }
05975
05976
05977
05978
05979
05980
05981 static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
05982 {
05983 int count = 0;
05984 struct member *m;
05985 struct ao2_iterator mem_iter;
05986 struct call_queue *q;
05987 char *option;
05988
05989 if (ast_strlen_zero(data)) {
05990 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
05991 return -1;
05992 }
05993
05994 if ((option = strchr(data, ',')))
05995 *option++ = '\0';
05996 else
05997 option = "logged";
05998 if ((q = load_realtime_queue(data))) {
05999 ao2_lock(q);
06000 if (!strcasecmp(option, "logged")) {
06001 mem_iter = ao2_iterator_init(q->members, 0);
06002 while ((m = ao2_iterator_next(&mem_iter))) {
06003
06004 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06005 count++;
06006 }
06007 ao2_ref(m, -1);
06008 }
06009 ao2_iterator_destroy(&mem_iter);
06010 } else if (!strcasecmp(option, "free")) {
06011 mem_iter = ao2_iterator_init(q->members, 0);
06012 while ((m = ao2_iterator_next(&mem_iter))) {
06013
06014 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
06015 count++;
06016 }
06017 ao2_ref(m, -1);
06018 }
06019 ao2_iterator_destroy(&mem_iter);
06020 } else if (!strcasecmp(option, "ready")) {
06021 time_t now;
06022 time(&now);
06023 mem_iter = ao2_iterator_init(q->members, 0);
06024 while ((m = ao2_iterator_next(&mem_iter))) {
06025
06026 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
06027 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
06028 count++;
06029 }
06030 ao2_ref(m, -1);
06031 }
06032 ao2_iterator_destroy(&mem_iter);
06033 } else
06034 count = q->membercount;
06035 ao2_unlock(q);
06036 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
06037 } else
06038 ast_log(LOG_WARNING, "queue %s was not found\n", data);
06039
06040 snprintf(buf, len, "%d", count);
06041
06042 return 0;
06043 }
06044
06045
06046
06047
06048
06049
06050 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06051 {
06052 int count = 0;
06053 struct member *m;
06054 struct call_queue *q;
06055 struct ao2_iterator mem_iter;
06056 static int depflag = 1;
06057
06058 if (depflag) {
06059 depflag = 0;
06060 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");
06061 }
06062
06063 if (ast_strlen_zero(data)) {
06064 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06065 return -1;
06066 }
06067
06068 if ((q = load_realtime_queue(data))) {
06069 ao2_lock(q);
06070 mem_iter = ao2_iterator_init(q->members, 0);
06071 while ((m = ao2_iterator_next(&mem_iter))) {
06072
06073 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06074 count++;
06075 }
06076 ao2_ref(m, -1);
06077 }
06078 ao2_iterator_destroy(&mem_iter);
06079 ao2_unlock(q);
06080 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
06081 } else
06082 ast_log(LOG_WARNING, "queue %s was not found\n", data);
06083
06084 snprintf(buf, len, "%d", count);
06085
06086 return 0;
06087 }
06088
06089
06090 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06091 {
06092 int count = 0;
06093 struct call_queue *q, tmpq = {
06094 .name = data,
06095 };
06096 struct ast_variable *var = NULL;
06097
06098 buf[0] = '\0';
06099
06100 if (ast_strlen_zero(data)) {
06101 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
06102 return -1;
06103 }
06104
06105 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
06106 ao2_lock(q);
06107 count = q->count;
06108 ao2_unlock(q);
06109 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
06110 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
06111
06112
06113
06114
06115 count = 0;
06116 ast_variables_destroy(var);
06117 } else
06118 ast_log(LOG_WARNING, "queue %s was not found\n", data);
06119
06120 snprintf(buf, len, "%d", count);
06121
06122 return 0;
06123 }
06124
06125
06126 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06127 {
06128 struct call_queue *q, tmpq = {
06129 .name = data,
06130 };
06131 struct member *m;
06132
06133
06134 buf[0] = '\0';
06135
06136 if (ast_strlen_zero(data)) {
06137 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
06138 return -1;
06139 }
06140
06141 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
06142 int buflen = 0, count = 0;
06143 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
06144
06145 ao2_lock(q);
06146 while ((m = ao2_iterator_next(&mem_iter))) {
06147
06148 if (count++) {
06149 strncat(buf + buflen, ",", len - buflen - 1);
06150 buflen++;
06151 }
06152 strncat(buf + buflen, m->interface, len - buflen - 1);
06153 buflen += strlen(m->interface);
06154
06155 if (buflen >= len - 2) {
06156 ao2_ref(m, -1);
06157 ast_log(LOG_WARNING, "Truncating list\n");
06158 break;
06159 }
06160 ao2_ref(m, -1);
06161 }
06162 ao2_iterator_destroy(&mem_iter);
06163 ao2_unlock(q);
06164 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
06165 } else
06166 ast_log(LOG_WARNING, "queue %s was not found\n", data);
06167
06168
06169 buf[len - 1] = '\0';
06170
06171 return 0;
06172 }
06173
06174
06175 static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06176 {
06177 int penalty;
06178 AST_DECLARE_APP_ARGS(args,
06179 AST_APP_ARG(queuename);
06180 AST_APP_ARG(interface);
06181 );
06182
06183 buf[0] = '\0';
06184
06185 if (ast_strlen_zero(data)) {
06186 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06187 return -1;
06188 }
06189
06190 AST_STANDARD_APP_ARGS(args, data);
06191
06192 if (args.argc < 2) {
06193 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06194 return -1;
06195 }
06196
06197 penalty = get_member_penalty (args.queuename, args.interface);
06198
06199 if (penalty >= 0)
06200 snprintf (buf, len, "%d", penalty);
06201
06202 return 0;
06203 }
06204
06205
06206 static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
06207 {
06208 int penalty;
06209 AST_DECLARE_APP_ARGS(args,
06210 AST_APP_ARG(queuename);
06211 AST_APP_ARG(interface);
06212 );
06213
06214 if (ast_strlen_zero(data)) {
06215 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06216 return -1;
06217 }
06218
06219 AST_STANDARD_APP_ARGS(args, data);
06220
06221 if (args.argc < 2) {
06222 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06223 return -1;
06224 }
06225
06226 penalty = atoi(value);
06227
06228 if (ast_strlen_zero(args.interface)) {
06229 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
06230 return -1;
06231 }
06232
06233
06234 if (set_member_penalty(args.queuename, args.interface, penalty)) {
06235 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
06236 return -1;
06237 }
06238
06239 return 0;
06240 }
06241
06242 static struct ast_custom_function queueexists_function = {
06243 .name = "QUEUE_EXISTS",
06244 .read = queue_function_exists,
06245 };
06246
06247 static struct ast_custom_function queuevar_function = {
06248 .name = "QUEUE_VARIABLES",
06249 .read = queue_function_var,
06250 };
06251
06252 static struct ast_custom_function queuemembercount_function = {
06253 .name = "QUEUE_MEMBER",
06254 .read = queue_function_qac,
06255 };
06256
06257 static struct ast_custom_function queuemembercount_dep = {
06258 .name = "QUEUE_MEMBER_COUNT",
06259 .read = queue_function_qac_dep,
06260 };
06261
06262 static struct ast_custom_function queuewaitingcount_function = {
06263 .name = "QUEUE_WAITING_COUNT",
06264 .read = queue_function_queuewaitingcount,
06265 };
06266
06267 static struct ast_custom_function queuememberlist_function = {
06268 .name = "QUEUE_MEMBER_LIST",
06269 .read = queue_function_queuememberlist,
06270 };
06271
06272 static struct ast_custom_function queuememberpenalty_function = {
06273 .name = "QUEUE_MEMBER_PENALTY",
06274 .read = queue_function_memberpenalty_read,
06275 .write = queue_function_memberpenalty_write,
06276 };
06277
06278
06279
06280
06281
06282
06283
06284 static int reload_queue_rules(int reload)
06285 {
06286 struct ast_config *cfg;
06287 struct rule_list *rl_iter, *new_rl;
06288 struct penalty_rule *pr_iter;
06289 char *rulecat = NULL;
06290 struct ast_variable *rulevar = NULL;
06291 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06292
06293 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
06294 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
06295 return AST_MODULE_LOAD_SUCCESS;
06296 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06297 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
06298 return AST_MODULE_LOAD_SUCCESS;
06299 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06300 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
06301 return AST_MODULE_LOAD_SUCCESS;
06302 }
06303
06304 AST_LIST_LOCK(&rule_lists);
06305 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
06306 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
06307 ast_free(pr_iter);
06308 ast_free(rl_iter);
06309 }
06310 while ((rulecat = ast_category_browse(cfg, rulecat))) {
06311 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
06312 AST_LIST_UNLOCK(&rule_lists);
06313 return AST_MODULE_LOAD_FAILURE;
06314 } else {
06315 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
06316 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
06317 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
06318 if(!strcasecmp(rulevar->name, "penaltychange"))
06319 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
06320 else
06321 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
06322 }
06323 }
06324 AST_LIST_UNLOCK(&rule_lists);
06325
06326 ast_config_destroy(cfg);
06327
06328 return AST_MODULE_LOAD_SUCCESS;
06329 }
06330
06331
06332 static void queue_set_global_params(struct ast_config *cfg)
06333 {
06334 const char *general_val = NULL;
06335 queue_persistent_members = 0;
06336 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
06337 queue_persistent_members = ast_true(general_val);
06338 autofill_default = 0;
06339 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
06340 autofill_default = ast_true(general_val);
06341 montype_default = 0;
06342 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
06343 if (!strcasecmp(general_val, "mixmonitor"))
06344 montype_default = 1;
06345 }
06346 update_cdr = 0;
06347 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
06348 update_cdr = ast_true(general_val);
06349 shared_lastcall = 0;
06350 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
06351 shared_lastcall = ast_true(general_val);
06352 }
06353
06354
06355
06356
06357
06358
06359
06360
06361
06362 static void reload_single_member(const char *memberdata, struct call_queue *q)
06363 {
06364 char *membername, *interface, *state_interface, *tmp;
06365 char *parse;
06366 struct member *cur, *newm;
06367 struct member tmpmem;
06368 int penalty;
06369 AST_DECLARE_APP_ARGS(args,
06370 AST_APP_ARG(interface);
06371 AST_APP_ARG(penalty);
06372 AST_APP_ARG(membername);
06373 AST_APP_ARG(state_interface);
06374 );
06375
06376 if (ast_strlen_zero(memberdata)) {
06377 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
06378 return;
06379 }
06380
06381
06382 parse = ast_strdupa(memberdata);
06383
06384 AST_STANDARD_APP_ARGS(args, parse);
06385
06386 interface = args.interface;
06387 if (!ast_strlen_zero(args.penalty)) {
06388 tmp = args.penalty;
06389 ast_strip(tmp);
06390 penalty = atoi(tmp);
06391 if (penalty < 0) {
06392 penalty = 0;
06393 }
06394 } else {
06395 penalty = 0;
06396 }
06397
06398 if (!ast_strlen_zero(args.membername)) {
06399 membername = args.membername;
06400 ast_strip(membername);
06401 } else {
06402 membername = interface;
06403 }
06404
06405 if (!ast_strlen_zero(args.state_interface)) {
06406 state_interface = args.state_interface;
06407 ast_strip(state_interface);
06408 } else {
06409 state_interface = interface;
06410 }
06411
06412
06413 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
06414 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
06415 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
06416 ao2_link(q->members, newm);
06417 ao2_ref(newm, -1);
06418 }
06419 newm = NULL;
06420
06421 if (cur) {
06422 ao2_ref(cur, -1);
06423 } else {
06424 q->membercount++;
06425 }
06426 }
06427
06428 static int mark_member_dead(void *obj, void *arg, int flags)
06429 {
06430 struct member *member = obj;
06431 if (!member->dynamic) {
06432 member->delme = 1;
06433 }
06434 return 0;
06435 }
06436
06437 static int kill_dead_members(void *obj, void *arg, int flags)
06438 {
06439 struct member *member = obj;
06440 struct call_queue *q = arg;
06441
06442 if (!member->delme) {
06443 if (member->dynamic) {
06444
06445
06446
06447 q->membercount++;
06448 }
06449 member->status = get_queue_member_status(member);
06450 return 0;
06451 } else {
06452 q->membercount--;
06453 return CMP_MATCH;
06454 }
06455 }
06456
06457
06458
06459
06460
06461
06462
06463
06464
06465
06466
06467
06468 static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
06469 {
06470 int new;
06471 struct call_queue *q = NULL;
06472
06473 struct call_queue tmpq = {
06474 .name = queuename,
06475 };
06476 const char *tmpvar;
06477 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06478 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
06479 int prev_weight = 0;
06480 struct ast_variable *var;
06481 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
06482 if (queue_reload) {
06483
06484 if (!(q = alloc_queue(queuename))) {
06485 return;
06486 }
06487 } else {
06488
06489
06490
06491 return;
06492 }
06493 new = 1;
06494 } else {
06495 new = 0;
06496 }
06497
06498 if (!new) {
06499 ao2_lock(q);
06500 prev_weight = q->weight ? 1 : 0;
06501 }
06502
06503 if (q->found) {
06504 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
06505 if (!new) {
06506
06507 ao2_unlock(q);
06508 }
06509 queue_t_unref(q, "We exist! Expiring temporary pointer");
06510 return;
06511 }
06512
06513
06514
06515
06516
06517 if (queue_reload) {
06518 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
06519 q->strategy = strat2int(tmpvar);
06520 if (q->strategy < 0) {
06521 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
06522 tmpvar, q->name);
06523 q->strategy = QUEUE_STRATEGY_RINGALL;
06524 }
06525 } else {
06526 q->strategy = QUEUE_STRATEGY_RINGALL;
06527 }
06528 init_queue(q);
06529 }
06530 if (member_reload) {
06531 q->membercount = 0;
06532 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
06533 }
06534 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
06535 if (member_reload && !strcasecmp(var->name, "member")) {
06536 reload_single_member(var->value, q);
06537 } else if (queue_reload) {
06538 queue_set_param(q, var->name, var->value, var->lineno, 1);
06539 }
06540 }
06541
06542
06543
06544 if (!q->weight && prev_weight) {
06545 ast_atomic_fetchadd_int(&use_weight, -1);
06546 }
06547 else if (q->weight && !prev_weight) {
06548 ast_atomic_fetchadd_int(&use_weight, +1);
06549 }
06550
06551
06552 if (member_reload) {
06553 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
06554 }
06555
06556 if (new) {
06557 queues_t_link(queues, q, "Add queue to container");
06558 } else {
06559 ao2_unlock(q);
06560 }
06561 queue_t_unref(q, "Expiring creation reference");
06562 }
06563
06564 static int mark_dead_and_unfound(void *obj, void *arg, int flags)
06565 {
06566 struct call_queue *q = obj;
06567 char *queuename = arg;
06568 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
06569 q->dead = 1;
06570 q->found = 0;
06571 }
06572 return 0;
06573 }
06574
06575 static int kill_dead_queues(void *obj, void *arg, int flags)
06576 {
06577 struct call_queue *q = obj;
06578 char *queuename = arg;
06579 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
06580 return CMP_MATCH;
06581 } else {
06582 return 0;
06583 }
06584 }
06585
06586
06587
06588
06589
06590
06591
06592
06593
06594
06595
06596
06597
06598 static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
06599 {
06600 struct ast_config *cfg;
06601 char *cat;
06602 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06603 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06604
06605 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
06606 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
06607 return -1;
06608 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06609 return 0;
06610 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06611 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
06612 return -1;
06613 }
06614
06615
06616 ao2_lock(queues);
06617
06618
06619
06620
06621 if (queue_reload) {
06622 ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
06623 }
06624
06625
06626 cat = NULL;
06627 while ((cat = ast_category_browse(cfg, cat)) ) {
06628 if (!strcasecmp(cat, "general") && queue_reload) {
06629 queue_set_global_params(cfg);
06630 continue;
06631 }
06632 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
06633 reload_single_queue(cfg, mask, cat);
06634 }
06635
06636 ast_config_destroy(cfg);
06637
06638 if (queue_reload) {
06639 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
06640 }
06641 ao2_unlock(queues);
06642 return 0;
06643 }
06644
06645
06646
06647
06648
06649
06650
06651
06652
06653
06654
06655
06656
06657
06658 static int clear_stats(const char *queuename)
06659 {
06660 struct call_queue *q;
06661 struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
06662 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06663 ao2_lock(q);
06664 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
06665 clear_queue(q);
06666 ao2_unlock(q);
06667 queue_t_unref(q, "Done with iterator");
06668 }
06669 ao2_iterator_destroy(&queue_iter);
06670 return 0;
06671 }
06672
06673
06674
06675
06676
06677
06678
06679
06680
06681
06682
06683
06684
06685
06686 static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
06687 {
06688 int res = 0;
06689
06690 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
06691 res |= reload_queue_rules(reload);
06692 }
06693 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
06694 res |= clear_stats(queuename);
06695 }
06696 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
06697 res |= reload_queues(reload, mask, queuename);
06698 }
06699 return res;
06700 }
06701
06702
06703 static void do_print(struct mansession *s, int fd, const char *str)
06704 {
06705 if (s)
06706 astman_append(s, "%s\r\n", str);
06707 else
06708 ast_cli(fd, "%s\n", str);
06709 }
06710
06711
06712
06713
06714
06715
06716
06717 static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
06718 {
06719 struct call_queue *q;
06720 struct ast_str *out = ast_str_alloca(240);
06721 int found = 0;
06722 time_t now = time(NULL);
06723 struct ao2_iterator queue_iter;
06724 struct ao2_iterator mem_iter;
06725
06726 if (argc != 2 && argc != 3)
06727 return CLI_SHOWUSAGE;
06728
06729 if (argc == 3) {
06730 if ((q = load_realtime_queue(argv[2]))) {
06731 queue_t_unref(q, "Done with temporary pointer");
06732 }
06733 } else if (ast_check_realtime("queues")) {
06734
06735
06736
06737 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
06738 char *queuename;
06739 if (cfg) {
06740 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
06741 if ((q = load_realtime_queue(queuename))) {
06742 queue_t_unref(q, "Done with temporary pointer");
06743 }
06744 }
06745 ast_config_destroy(cfg);
06746 }
06747 }
06748
06749 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
06750 ao2_lock(queues);
06751 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06752 float sl;
06753 struct call_queue *realtime_queue = NULL;
06754
06755 ao2_lock(q);
06756
06757
06758
06759
06760 if (q->realtime && !(realtime_queue = load_realtime_queue(q->name))) {
06761 ao2_unlock(q);
06762 queue_t_unref(q, "Done with iterator");
06763 continue;
06764 } else if (q->realtime) {
06765 queue_t_unref(realtime_queue, "Queue is already in memory");
06766 }
06767 if (argc == 3 && strcasecmp(q->name, argv[2])) {
06768 ao2_unlock(q);
06769 queue_t_unref(q, "Done with iterator");
06770 continue;
06771 }
06772 found = 1;
06773
06774 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
06775 if (q->maxlen)
06776 ast_str_append(&out, 0, "%d", q->maxlen);
06777 else
06778 ast_str_append(&out, 0, "unlimited");
06779 sl = 0;
06780 if (q->callscompleted > 0)
06781 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06782 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
06783 int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
06784 q->callscompleted, q->callsabandoned,sl,q->servicelevel);
06785 do_print(s, fd, ast_str_buffer(out));
06786 if (!ao2_container_count(q->members))
06787 do_print(s, fd, " No Members");
06788 else {
06789 struct member *mem;
06790
06791 do_print(s, fd, " Members: ");
06792 mem_iter = ao2_iterator_init(q->members, 0);
06793 while ((mem = ao2_iterator_next(&mem_iter))) {
06794 ast_str_set(&out, 0, " %s", mem->membername);
06795 if (strcasecmp(mem->membername, mem->interface)) {
06796 ast_str_append(&out, 0, " (%s)", mem->interface);
06797 }
06798 if (mem->penalty)
06799 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
06800 ast_str_append(&out, 0, "%s%s%s (%s)",
06801 mem->dynamic ? " (dynamic)" : "",
06802 mem->realtime ? " (realtime)" : "",
06803 mem->paused ? " (paused)" : "",
06804 ast_devstate2str(mem->status));
06805 if (mem->calls)
06806 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
06807 mem->calls, (long) (time(NULL) - mem->lastcall));
06808 else
06809 ast_str_append(&out, 0, " has taken no calls yet");
06810 do_print(s, fd, ast_str_buffer(out));
06811 ao2_ref(mem, -1);
06812 }
06813 ao2_iterator_destroy(&mem_iter);
06814 }
06815 if (!q->head)
06816 do_print(s, fd, " No Callers");
06817 else {
06818 struct queue_ent *qe;
06819 int pos = 1;
06820
06821 do_print(s, fd, " Callers: ");
06822 for (qe = q->head; qe; qe = qe->next) {
06823 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
06824 pos++, qe->chan->name, (long) (now - qe->start) / 60,
06825 (long) (now - qe->start) % 60, qe->prio);
06826 do_print(s, fd, ast_str_buffer(out));
06827 }
06828 }
06829 do_print(s, fd, "");
06830 ao2_unlock(q);
06831 queue_t_unref(q, "Done with iterator");
06832 }
06833 ao2_iterator_destroy(&queue_iter);
06834 ao2_unlock(queues);
06835 if (!found) {
06836 if (argc == 3)
06837 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
06838 else
06839 ast_str_set(&out, 0, "No queues.");
06840 do_print(s, fd, ast_str_buffer(out));
06841 }
06842 return CLI_SUCCESS;
06843 }
06844
06845 static char *complete_queue(const char *line, const char *word, int pos, int state)
06846 {
06847 struct call_queue *q;
06848 char *ret = NULL;
06849 int which = 0;
06850 int wordlen = strlen(word);
06851 struct ao2_iterator queue_iter;
06852
06853 queue_iter = ao2_iterator_init(queues, 0);
06854 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06855 if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
06856 ret = ast_strdup(q->name);
06857 queue_t_unref(q, "Done with iterator");
06858 break;
06859 }
06860 queue_t_unref(q, "Done with iterator");
06861 }
06862 ao2_iterator_destroy(&queue_iter);
06863
06864 return ret;
06865 }
06866
06867 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
06868 {
06869 if (pos == 2)
06870 return complete_queue(line, word, pos, state);
06871 return NULL;
06872 }
06873
06874 static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06875 {
06876 switch ( cmd ) {
06877 case CLI_INIT:
06878 e->command = "queue show";
06879 e->usage =
06880 "Usage: queue show\n"
06881 " Provides summary information on a specified queue.\n";
06882 return NULL;
06883 case CLI_GENERATE:
06884 return complete_queue_show(a->line, a->word, a->pos, a->n);
06885 }
06886
06887 return __queues_show(NULL, a->fd, a->argc, a->argv);
06888 }
06889
06890
06891
06892
06893 static int manager_queues_show(struct mansession *s, const struct message *m)
06894 {
06895 static const char * const a[] = { "queue", "show" };
06896
06897 __queues_show(s, -1, 2, a);
06898 astman_append(s, "\r\n\r\n");
06899
06900 return RESULT_SUCCESS;
06901 }
06902
06903 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
06904 {
06905 const char *rule = astman_get_header(m, "Rule");
06906 struct rule_list *rl_iter;
06907 struct penalty_rule *pr_iter;
06908
06909 AST_LIST_LOCK(&rule_lists);
06910 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
06911 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
06912 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
06913 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
06914 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 );
06915 }
06916 if (!ast_strlen_zero(rule))
06917 break;
06918 }
06919 }
06920 AST_LIST_UNLOCK(&rule_lists);
06921
06922 astman_append(s, "\r\n\r\n");
06923
06924 return RESULT_SUCCESS;
06925 }
06926
06927
06928 static int manager_queues_summary(struct mansession *s, const struct message *m)
06929 {
06930 time_t now;
06931 int qmemcount = 0;
06932 int qmemavail = 0;
06933 int qchancount = 0;
06934 int qlongestholdtime = 0;
06935 const char *id = astman_get_header(m, "ActionID");
06936 const char *queuefilter = astman_get_header(m, "Queue");
06937 char idText[256] = "";
06938 struct call_queue *q;
06939 struct queue_ent *qe;
06940 struct member *mem;
06941 struct ao2_iterator queue_iter;
06942 struct ao2_iterator mem_iter;
06943
06944 astman_send_ack(s, m, "Queue summary will follow");
06945 time(&now);
06946 if (!ast_strlen_zero(id))
06947 snprintf(idText, 256, "ActionID: %s\r\n", id);
06948 queue_iter = ao2_iterator_init(queues, 0);
06949 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06950 ao2_lock(q);
06951
06952
06953 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
06954
06955 qmemcount = 0;
06956 qmemavail = 0;
06957 qchancount = 0;
06958 qlongestholdtime = 0;
06959
06960
06961 mem_iter = ao2_iterator_init(q->members, 0);
06962 while ((mem = ao2_iterator_next(&mem_iter))) {
06963 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
06964 ++qmemcount;
06965 if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
06966 ++qmemavail;
06967 }
06968 }
06969 ao2_ref(mem, -1);
06970 }
06971 ao2_iterator_destroy(&mem_iter);
06972 for (qe = q->head; qe; qe = qe->next) {
06973 if ((now - qe->start) > qlongestholdtime) {
06974 qlongestholdtime = now - qe->start;
06975 }
06976 ++qchancount;
06977 }
06978 astman_append(s, "Event: QueueSummary\r\n"
06979 "Queue: %s\r\n"
06980 "LoggedIn: %d\r\n"
06981 "Available: %d\r\n"
06982 "Callers: %d\r\n"
06983 "HoldTime: %d\r\n"
06984 "TalkTime: %d\r\n"
06985 "LongestHoldTime: %d\r\n"
06986 "%s"
06987 "\r\n",
06988 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
06989 }
06990 ao2_unlock(q);
06991 queue_t_unref(q, "Done with iterator");
06992 }
06993 ao2_iterator_destroy(&queue_iter);
06994 astman_append(s,
06995 "Event: QueueSummaryComplete\r\n"
06996 "%s"
06997 "\r\n", idText);
06998
06999 return RESULT_SUCCESS;
07000 }
07001
07002
07003 static int manager_queues_status(struct mansession *s, const struct message *m)
07004 {
07005 time_t now;
07006 int pos;
07007 const char *id = astman_get_header(m,"ActionID");
07008 const char *queuefilter = astman_get_header(m,"Queue");
07009 const char *memberfilter = astman_get_header(m,"Member");
07010 char idText[256] = "";
07011 struct call_queue *q;
07012 struct queue_ent *qe;
07013 float sl = 0;
07014 struct member *mem;
07015 struct ao2_iterator queue_iter;
07016 struct ao2_iterator mem_iter;
07017
07018 astman_send_ack(s, m, "Queue status will follow");
07019 time(&now);
07020 if (!ast_strlen_zero(id))
07021 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07022
07023 queue_iter = ao2_iterator_init(queues, 0);
07024 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07025 ao2_lock(q);
07026
07027
07028 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07029 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
07030 astman_append(s, "Event: QueueParams\r\n"
07031 "Queue: %s\r\n"
07032 "Max: %d\r\n"
07033 "Strategy: %s\r\n"
07034 "Calls: %d\r\n"
07035 "Holdtime: %d\r\n"
07036 "TalkTime: %d\r\n"
07037 "Completed: %d\r\n"
07038 "Abandoned: %d\r\n"
07039 "ServiceLevel: %d\r\n"
07040 "ServicelevelPerf: %2.1f\r\n"
07041 "Weight: %d\r\n"
07042 "%s"
07043 "\r\n",
07044 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
07045 q->callsabandoned, q->servicelevel, sl, q->weight, idText);
07046
07047 mem_iter = ao2_iterator_init(q->members, 0);
07048 while ((mem = ao2_iterator_next(&mem_iter))) {
07049 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
07050 astman_append(s, "Event: QueueMember\r\n"
07051 "Queue: %s\r\n"
07052 "Name: %s\r\n"
07053 "Location: %s\r\n"
07054 "Membership: %s\r\n"
07055 "Penalty: %d\r\n"
07056 "CallsTaken: %d\r\n"
07057 "LastCall: %d\r\n"
07058 "Status: %d\r\n"
07059 "Paused: %d\r\n"
07060 "%s"
07061 "\r\n",
07062 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
07063 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
07064 }
07065 ao2_ref(mem, -1);
07066 }
07067 ao2_iterator_destroy(&mem_iter);
07068
07069 pos = 1;
07070 for (qe = q->head; qe; qe = qe->next) {
07071 astman_append(s, "Event: QueueEntry\r\n"
07072 "Queue: %s\r\n"
07073 "Position: %d\r\n"
07074 "Channel: %s\r\n"
07075 "Uniqueid: %s\r\n"
07076 "CallerIDNum: %s\r\n"
07077 "CallerIDName: %s\r\n"
07078 "Wait: %ld\r\n"
07079 "%s"
07080 "\r\n",
07081 q->name, pos++, qe->chan->name, qe->chan->uniqueid,
07082 S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
07083 S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
07084 (long) (now - qe->start), idText);
07085 }
07086 }
07087 ao2_unlock(q);
07088 queue_t_unref(q, "Done with iterator");
07089 }
07090 ao2_iterator_destroy(&queue_iter);
07091
07092 astman_append(s,
07093 "Event: QueueStatusComplete\r\n"
07094 "%s"
07095 "\r\n",idText);
07096
07097 return RESULT_SUCCESS;
07098 }
07099
07100 static int manager_add_queue_member(struct mansession *s, const struct message *m)
07101 {
07102 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
07103 int paused, penalty = 0;
07104
07105 queuename = astman_get_header(m, "Queue");
07106 interface = astman_get_header(m, "Interface");
07107 penalty_s = astman_get_header(m, "Penalty");
07108 paused_s = astman_get_header(m, "Paused");
07109 membername = astman_get_header(m, "MemberName");
07110 state_interface = astman_get_header(m, "StateInterface");
07111
07112 if (ast_strlen_zero(queuename)) {
07113 astman_send_error(s, m, "'Queue' not specified.");
07114 return 0;
07115 }
07116
07117 if (ast_strlen_zero(interface)) {
07118 astman_send_error(s, m, "'Interface' not specified.");
07119 return 0;
07120 }
07121
07122 if (ast_strlen_zero(penalty_s))
07123 penalty = 0;
07124 else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
07125 penalty = 0;
07126
07127 if (ast_strlen_zero(paused_s))
07128 paused = 0;
07129 else
07130 paused = abs(ast_true(paused_s));
07131
07132 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
07133 case RES_OKAY:
07134 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
07135 astman_send_ack(s, m, "Added interface to queue");
07136 break;
07137 case RES_EXISTS:
07138 astman_send_error(s, m, "Unable to add interface: Already there");
07139 break;
07140 case RES_NOSUCHQUEUE:
07141 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
07142 break;
07143 case RES_OUTOFMEMORY:
07144 astman_send_error(s, m, "Out of memory");
07145 break;
07146 }
07147
07148 return 0;
07149 }
07150
07151 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
07152 {
07153 const char *queuename, *interface;
07154
07155 queuename = astman_get_header(m, "Queue");
07156 interface = astman_get_header(m, "Interface");
07157
07158 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
07159 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
07160 return 0;
07161 }
07162
07163 switch (remove_from_queue(queuename, interface)) {
07164 case RES_OKAY:
07165 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
07166 astman_send_ack(s, m, "Removed interface from queue");
07167 break;
07168 case RES_EXISTS:
07169 astman_send_error(s, m, "Unable to remove interface: Not there");
07170 break;
07171 case RES_NOSUCHQUEUE:
07172 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
07173 break;
07174 case RES_OUTOFMEMORY:
07175 astman_send_error(s, m, "Out of memory");
07176 break;
07177 case RES_NOT_DYNAMIC:
07178 astman_send_error(s, m, "Member not dynamic");
07179 break;
07180 }
07181
07182 return 0;
07183 }
07184
07185 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
07186 {
07187 const char *queuename, *interface, *paused_s, *reason;
07188 int paused;
07189
07190 interface = astman_get_header(m, "Interface");
07191 paused_s = astman_get_header(m, "Paused");
07192 queuename = astman_get_header(m, "Queue");
07193 reason = astman_get_header(m, "Reason");
07194
07195 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
07196 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
07197 return 0;
07198 }
07199
07200 paused = abs(ast_true(paused_s));
07201
07202 if (set_member_paused(queuename, interface, reason, paused))
07203 astman_send_error(s, m, "Interface not found");
07204 else
07205 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
07206 return 0;
07207 }
07208
07209 static int manager_queue_log_custom(struct mansession *s, const struct message *m)
07210 {
07211 const char *queuename, *event, *message, *interface, *uniqueid;
07212
07213 queuename = astman_get_header(m, "Queue");
07214 uniqueid = astman_get_header(m, "UniqueId");
07215 interface = astman_get_header(m, "Interface");
07216 event = astman_get_header(m, "Event");
07217 message = astman_get_header(m, "Message");
07218
07219 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
07220 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
07221 return 0;
07222 }
07223
07224 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
07225 astman_send_ack(s, m, "Event added successfully");
07226
07227 return 0;
07228 }
07229
07230 static int manager_queue_reload(struct mansession *s, const struct message *m)
07231 {
07232 struct ast_flags mask = {0,};
07233 const char *queuename = NULL;
07234 int header_found = 0;
07235
07236 queuename = astman_get_header(m, "Queue");
07237 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
07238 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07239 header_found = 1;
07240 }
07241 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
07242 ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07243 header_found = 1;
07244 }
07245 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
07246 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07247 header_found = 1;
07248 }
07249
07250 if (!header_found) {
07251 ast_set_flag(&mask, AST_FLAGS_ALL);
07252 }
07253
07254 if (!reload_handler(1, &mask, queuename)) {
07255 astman_send_ack(s, m, "Queue reloaded successfully");
07256 } else {
07257 astman_send_error(s, m, "Error encountered while reloading queue");
07258 }
07259 return 0;
07260 }
07261
07262 static int manager_queue_reset(struct mansession *s, const struct message *m)
07263 {
07264 const char *queuename = NULL;
07265 struct ast_flags mask = {QUEUE_RESET_STATS,};
07266
07267 queuename = astman_get_header(m, "Queue");
07268
07269 if (!reload_handler(1, &mask, queuename)) {
07270 astman_send_ack(s, m, "Queue stats reset successfully");
07271 } else {
07272 astman_send_error(s, m, "Error encountered while resetting queue stats");
07273 }
07274 return 0;
07275 }
07276
07277 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
07278 {
07279
07280 switch (pos) {
07281 case 3:
07282 return NULL;
07283 case 4:
07284 return state == 0 ? ast_strdup("to") : NULL;
07285 case 5:
07286 return complete_queue(line, word, pos, state);
07287 case 6:
07288 return state == 0 ? ast_strdup("penalty") : NULL;
07289 case 7:
07290 if (state < 100) {
07291 char *num;
07292 if ((num = ast_malloc(3))) {
07293 sprintf(num, "%d", state);
07294 }
07295 return num;
07296 } else {
07297 return NULL;
07298 }
07299 case 8:
07300 return state == 0 ? ast_strdup("as") : NULL;
07301 case 9:
07302 return NULL;
07303 default:
07304 return NULL;
07305 }
07306 }
07307
07308 static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
07309 {
07310 const char *queuename, *interface, *penalty_s;
07311 int penalty;
07312
07313 interface = astman_get_header(m, "Interface");
07314 penalty_s = astman_get_header(m, "Penalty");
07315
07316 queuename = astman_get_header(m, "Queue");
07317
07318 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
07319 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
07320 return 0;
07321 }
07322
07323 penalty = atoi(penalty_s);
07324
07325 if (set_member_penalty((char *)queuename, (char *)interface, penalty))
07326 astman_send_error(s, m, "Invalid interface, queuename or penalty");
07327 else
07328 astman_send_ack(s, m, "Interface penalty set successfully");
07329
07330 return 0;
07331 }
07332
07333 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07334 {
07335 const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
07336 int penalty;
07337
07338 switch ( cmd ) {
07339 case CLI_INIT:
07340 e->command = "queue add member";
07341 e->usage =
07342 "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
07343 " Add a channel to a queue with optionally: a penalty, membername and a state_interface\n";
07344 return NULL;
07345 case CLI_GENERATE:
07346 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
07347 }
07348
07349 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
07350 return CLI_SHOWUSAGE;
07351 } else if (strcmp(a->argv[4], "to")) {
07352 return CLI_SHOWUSAGE;
07353 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
07354 return CLI_SHOWUSAGE;
07355 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
07356 return CLI_SHOWUSAGE;
07357 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
07358 return CLI_SHOWUSAGE;
07359 }
07360
07361 queuename = a->argv[5];
07362 interface = a->argv[3];
07363 if (a->argc >= 8) {
07364 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
07365 if (penalty < 0) {
07366 ast_cli(a->fd, "Penalty must be >= 0\n");
07367 penalty = 0;
07368 }
07369 } else {
07370 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
07371 penalty = 0;
07372 }
07373 } else {
07374 penalty = 0;
07375 }
07376
07377 if (a->argc >= 10) {
07378 membername = a->argv[9];
07379 }
07380
07381 if (a->argc >= 12) {
07382 state_interface = a->argv[11];
07383 }
07384
07385 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
07386 case RES_OKAY:
07387 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
07388 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
07389 return CLI_SUCCESS;
07390 case RES_EXISTS:
07391 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
07392 return CLI_FAILURE;
07393 case RES_NOSUCHQUEUE:
07394 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
07395 return CLI_FAILURE;
07396 case RES_OUTOFMEMORY:
07397 ast_cli(a->fd, "Out of memory\n");
07398 return CLI_FAILURE;
07399 case RES_NOT_DYNAMIC:
07400 ast_cli(a->fd, "Member not dynamic\n");
07401 return CLI_FAILURE;
07402 default:
07403 return CLI_FAILURE;
07404 }
07405 }
07406
07407 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
07408 {
07409 int which = 0;
07410 struct call_queue *q;
07411 struct member *m;
07412 struct ao2_iterator queue_iter;
07413 struct ao2_iterator mem_iter;
07414 int wordlen = strlen(word);
07415
07416
07417 if (pos > 5 || pos < 3)
07418 return NULL;
07419 if (pos == 4)
07420 return (state == 0 ? ast_strdup("from") : NULL);
07421
07422 if (pos == 5)
07423 return complete_queue(line, word, pos, state);
07424
07425
07426 queue_iter = ao2_iterator_init(queues, 0);
07427 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07428 ao2_lock(q);
07429 mem_iter = ao2_iterator_init(q->members, 0);
07430 while ((m = ao2_iterator_next(&mem_iter))) {
07431 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
07432 char *tmp;
07433 ao2_unlock(q);
07434 tmp = ast_strdup(m->interface);
07435 ao2_ref(m, -1);
07436 queue_t_unref(q, "Done with iterator, returning interface name");
07437 ao2_iterator_destroy(&mem_iter);
07438 ao2_iterator_destroy(&queue_iter);
07439 return tmp;
07440 }
07441 ao2_ref(m, -1);
07442 }
07443 ao2_iterator_destroy(&mem_iter);
07444 ao2_unlock(q);
07445 queue_t_unref(q, "Done with iterator");
07446 }
07447 ao2_iterator_destroy(&queue_iter);
07448
07449 return NULL;
07450 }
07451
07452 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07453 {
07454 const char *queuename, *interface;
07455
07456 switch (cmd) {
07457 case CLI_INIT:
07458 e->command = "queue remove member";
07459 e->usage =
07460 "Usage: queue remove member <channel> from <queue>\n"
07461 " Remove a specific channel from a queue.\n";
07462 return NULL;
07463 case CLI_GENERATE:
07464 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
07465 }
07466
07467 if (a->argc != 6) {
07468 return CLI_SHOWUSAGE;
07469 } else if (strcmp(a->argv[4], "from")) {
07470 return CLI_SHOWUSAGE;
07471 }
07472
07473 queuename = a->argv[5];
07474 interface = a->argv[3];
07475
07476 switch (remove_from_queue(queuename, interface)) {
07477 case RES_OKAY:
07478 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
07479 ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
07480 return CLI_SUCCESS;
07481 case RES_EXISTS:
07482 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
07483 return CLI_FAILURE;
07484 case RES_NOSUCHQUEUE:
07485 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
07486 return CLI_FAILURE;
07487 case RES_OUTOFMEMORY:
07488 ast_cli(a->fd, "Out of memory\n");
07489 return CLI_FAILURE;
07490 case RES_NOT_DYNAMIC:
07491 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
07492 return CLI_FAILURE;
07493 default:
07494 return CLI_FAILURE;
07495 }
07496 }
07497
07498 static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
07499 {
07500
07501 switch (pos) {
07502 case 3:
07503 return NULL;
07504 case 4:
07505 return state == 0 ? ast_strdup("queue") : NULL;
07506 case 5:
07507 return complete_queue(line, word, pos, state);
07508 case 6:
07509 return state == 0 ? ast_strdup("reason") : NULL;
07510 case 7:
07511 return NULL;
07512 default:
07513 return NULL;
07514 }
07515 }
07516
07517 static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07518 {
07519 const char *queuename, *interface, *reason;
07520 int paused;
07521
07522 switch (cmd) {
07523 case CLI_INIT:
07524 e->command = "queue {pause|unpause} member";
07525 e->usage =
07526 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
07527 " Pause or unpause a queue member. Not specifying a particular queue\n"
07528 " will pause or unpause a member across all queues to which the member\n"
07529 " belongs.\n";
07530 return NULL;
07531 case CLI_GENERATE:
07532 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
07533 }
07534
07535 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
07536 return CLI_SHOWUSAGE;
07537 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
07538 return CLI_SHOWUSAGE;
07539 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
07540 return CLI_SHOWUSAGE;
07541 }
07542
07543
07544 interface = a->argv[3];
07545 queuename = a->argc >= 6 ? a->argv[5] : NULL;
07546 reason = a->argc == 8 ? a->argv[7] : NULL;
07547 paused = !strcasecmp(a->argv[1], "pause");
07548
07549 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
07550 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
07551 if (!ast_strlen_zero(queuename))
07552 ast_cli(a->fd, " in queue '%s'", queuename);
07553 if (!ast_strlen_zero(reason))
07554 ast_cli(a->fd, " for reason '%s'", reason);
07555 ast_cli(a->fd, "\n");
07556 return CLI_SUCCESS;
07557 } else {
07558 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
07559 if (!ast_strlen_zero(queuename))
07560 ast_cli(a->fd, " in queue '%s'", queuename);
07561 if (!ast_strlen_zero(reason))
07562 ast_cli(a->fd, " for reason '%s'", reason);
07563 ast_cli(a->fd, "\n");
07564 return CLI_FAILURE;
07565 }
07566 }
07567
07568 static char *complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
07569 {
07570
07571 switch (pos) {
07572 case 4:
07573 if (state == 0) {
07574 return ast_strdup("on");
07575 } else {
07576 return NULL;
07577 }
07578 case 6:
07579 if (state == 0) {
07580 return ast_strdup("in");
07581 } else {
07582 return NULL;
07583 }
07584 case 7:
07585 return complete_queue(line, word, pos, state);
07586 default:
07587 return NULL;
07588 }
07589 }
07590
07591 static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07592 {
07593 const char *queuename = NULL, *interface;
07594 int penalty = 0;
07595
07596 switch (cmd) {
07597 case CLI_INIT:
07598 e->command = "queue set penalty";
07599 e->usage =
07600 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
07601 " Set a member's penalty in the queue specified. If no queue is specified\n"
07602 " then that interface's penalty is set in all queues to which that interface is a member\n";
07603 return NULL;
07604 case CLI_GENERATE:
07605 return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
07606 }
07607
07608 if (a->argc != 6 && a->argc != 8) {
07609 return CLI_SHOWUSAGE;
07610 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
07611 return CLI_SHOWUSAGE;
07612 }
07613
07614 if (a->argc == 8)
07615 queuename = a->argv[7];
07616 interface = a->argv[5];
07617 penalty = atoi(a->argv[3]);
07618
07619 switch (set_member_penalty(queuename, interface, penalty)) {
07620 case RESULT_SUCCESS:
07621 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07622 return CLI_SUCCESS;
07623 case RESULT_FAILURE:
07624 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07625 return CLI_FAILURE;
07626 default:
07627 return CLI_FAILURE;
07628 }
07629 }
07630
07631 static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
07632 {
07633 int which = 0;
07634 struct rule_list *rl_iter;
07635 int wordlen = strlen(word);
07636 char *ret = NULL;
07637 if (pos != 3) {
07638 return NULL;
07639 }
07640
07641 AST_LIST_LOCK(&rule_lists);
07642 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07643 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
07644 ret = ast_strdup(rl_iter->name);
07645 break;
07646 }
07647 }
07648 AST_LIST_UNLOCK(&rule_lists);
07649
07650 return ret;
07651 }
07652
07653 static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07654 {
07655 const char *rule;
07656 struct rule_list *rl_iter;
07657 struct penalty_rule *pr_iter;
07658 switch (cmd) {
07659 case CLI_INIT:
07660 e->command = "queue show rules";
07661 e->usage =
07662 "Usage: queue show rules [rulename]\n"
07663 " Show the list of rules associated with rulename. If no\n"
07664 " rulename is specified, list all rules defined in queuerules.conf\n";
07665 return NULL;
07666 case CLI_GENERATE:
07667 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
07668 }
07669
07670 if (a->argc != 3 && a->argc != 4)
07671 return CLI_SHOWUSAGE;
07672
07673 rule = a->argc == 4 ? a->argv[3] : "";
07674 AST_LIST_LOCK(&rule_lists);
07675 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07676 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
07677 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
07678 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07679 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value);
07680 }
07681 }
07682 }
07683 AST_LIST_UNLOCK(&rule_lists);
07684 return CLI_SUCCESS;
07685 }
07686
07687 static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07688 {
07689 struct ast_flags mask = {QUEUE_RESET_STATS,};
07690 int i;
07691
07692 switch (cmd) {
07693 case CLI_INIT:
07694 e->command = "queue reset stats";
07695 e->usage =
07696 "Usage: queue reset stats [<queuenames>]\n"
07697 "\n"
07698 "Issuing this command will reset statistics for\n"
07699 "<queuenames>, or for all queues if no queue is\n"
07700 "specified.\n";
07701 return NULL;
07702 case CLI_GENERATE:
07703 if (a->pos >= 3) {
07704 return complete_queue(a->line, a->word, a->pos, a->n);
07705 } else {
07706 return NULL;
07707 }
07708 }
07709
07710 if (a->argc < 3) {
07711 return CLI_SHOWUSAGE;
07712 }
07713
07714 if (a->argc == 3) {
07715 reload_handler(1, &mask, NULL);
07716 return CLI_SUCCESS;
07717 }
07718
07719 for (i = 3; i < a->argc; ++i) {
07720 reload_handler(1, &mask, a->argv[i]);
07721 }
07722
07723 return CLI_SUCCESS;
07724 }
07725
07726 static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07727 {
07728 struct ast_flags mask = {0,};
07729 int i;
07730
07731 switch (cmd) {
07732 case CLI_INIT:
07733 e->command = "queue reload {parameters|members|rules|all}";
07734 e->usage =
07735 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
07736 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
07737 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
07738 "specified in order to know what information to reload. Below is an explanation\n"
07739 "of each of these qualifiers.\n"
07740 "\n"
07741 "\t'members' - reload queue members from queues.conf\n"
07742 "\t'parameters' - reload all queue options except for queue members\n"
07743 "\t'rules' - reload the queuerules.conf file\n"
07744 "\t'all' - reload queue rules, parameters, and members\n"
07745 "\n"
07746 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
07747 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
07748 "one queue is specified when using this command, reloading queue rules may cause\n"
07749 "other queues to be affected\n";
07750 return NULL;
07751 case CLI_GENERATE:
07752 if (a->pos >= 3) {
07753 return complete_queue(a->line, a->word, a->pos, a->n);
07754 } else {
07755 return NULL;
07756 }
07757 }
07758
07759 if (a->argc < 3)
07760 return CLI_SHOWUSAGE;
07761
07762 if (!strcasecmp(a->argv[2], "rules")) {
07763 ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07764 } else if (!strcasecmp(a->argv[2], "members")) {
07765 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07766 } else if (!strcasecmp(a->argv[2], "parameters")) {
07767 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07768 } else if (!strcasecmp(a->argv[2], "all")) {
07769 ast_set_flag(&mask, AST_FLAGS_ALL);
07770 }
07771
07772 if (a->argc == 3) {
07773 reload_handler(1, &mask, NULL);
07774 return CLI_SUCCESS;
07775 }
07776
07777 for (i = 3; i < a->argc; ++i) {
07778 reload_handler(1, &mask, a->argv[i]);
07779 }
07780
07781 return CLI_SUCCESS;
07782 }
07783
07784 static const char qpm_cmd_usage[] =
07785 "Usage: queue pause member <channel> in <queue> reason <reason>\n";
07786
07787 static const char qum_cmd_usage[] =
07788 "Usage: queue unpause member <channel> in <queue> reason <reason>\n";
07789
07790 static const char qsmp_cmd_usage[] =
07791 "Usage: queue set member penalty <channel> from <queue> <penalty>\n";
07792
07793 static struct ast_cli_entry cli_queue[] = {
07794 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
07795 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
07796 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
07797 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
07798 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
07799 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
07800 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
07801 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
07802 };
07803
07804
07805 #define DATA_EXPORT_CALL_QUEUE(MEMBER) \
07806 MEMBER(call_queue, name, AST_DATA_STRING) \
07807 MEMBER(call_queue, moh, AST_DATA_STRING) \
07808 MEMBER(call_queue, announce, AST_DATA_STRING) \
07809 MEMBER(call_queue, context, AST_DATA_STRING) \
07810 MEMBER(call_queue, membermacro, AST_DATA_STRING) \
07811 MEMBER(call_queue, membergosub, AST_DATA_STRING) \
07812 MEMBER(call_queue, defaultrule, AST_DATA_STRING) \
07813 MEMBER(call_queue, sound_next, AST_DATA_STRING) \
07814 MEMBER(call_queue, sound_thereare, AST_DATA_STRING) \
07815 MEMBER(call_queue, sound_calls, AST_DATA_STRING) \
07816 MEMBER(call_queue, queue_quantity1, AST_DATA_STRING) \
07817 MEMBER(call_queue, queue_quantity2, AST_DATA_STRING) \
07818 MEMBER(call_queue, sound_holdtime, AST_DATA_STRING) \
07819 MEMBER(call_queue, sound_minutes, AST_DATA_STRING) \
07820 MEMBER(call_queue, sound_minute, AST_DATA_STRING) \
07821 MEMBER(call_queue, sound_seconds, AST_DATA_STRING) \
07822 MEMBER(call_queue, sound_thanks, AST_DATA_STRING) \
07823 MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING) \
07824 MEMBER(call_queue, sound_reporthold, AST_DATA_STRING) \
07825 MEMBER(call_queue, dead, AST_DATA_BOOLEAN) \
07826 MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN) \
07827 MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN) \
07828 MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN) \
07829 MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN) \
07830 MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN) \
07831 MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN) \
07832 MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN) \
07833 MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN) \
07834 MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER) \
07835 MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN) \
07836 MEMBER(call_queue, realtime, AST_DATA_BOOLEAN) \
07837 MEMBER(call_queue, found, AST_DATA_BOOLEAN) \
07838 MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \
07839 MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS) \
07840 MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS) \
07841 MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS) \
07842 MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER) \
07843 MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER) \
07844 MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS) \
07845 MEMBER(call_queue, holdtime, AST_DATA_SECONDS) \
07846 MEMBER(call_queue, talktime, AST_DATA_SECONDS) \
07847 MEMBER(call_queue, callscompleted, AST_DATA_INTEGER) \
07848 MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER) \
07849 MEMBER(call_queue, servicelevel, AST_DATA_INTEGER) \
07850 MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \
07851 MEMBER(call_queue, monfmt, AST_DATA_STRING) \
07852 MEMBER(call_queue, montype, AST_DATA_INTEGER) \
07853 MEMBER(call_queue, count, AST_DATA_INTEGER) \
07854 MEMBER(call_queue, maxlen, AST_DATA_INTEGER) \
07855 MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS) \
07856 MEMBER(call_queue, retry, AST_DATA_SECONDS) \
07857 MEMBER(call_queue, timeout, AST_DATA_SECONDS) \
07858 MEMBER(call_queue, weight, AST_DATA_INTEGER) \
07859 MEMBER(call_queue, autopause, AST_DATA_INTEGER) \
07860 MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER) \
07861 MEMBER(call_queue, rrpos, AST_DATA_INTEGER) \
07862 MEMBER(call_queue, memberdelay, AST_DATA_INTEGER) \
07863 MEMBER(call_queue, autofill, AST_DATA_INTEGER) \
07864 MEMBER(call_queue, members, AST_DATA_CONTAINER) \
07865 MEMBER(call_queue, membercount, AST_DATA_INTEGER)
07866
07867 AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE);
07868
07869
07870 #define DATA_EXPORT_MEMBER(MEMBER) \
07871 MEMBER(member, interface, AST_DATA_STRING) \
07872 MEMBER(member, state_interface, AST_DATA_STRING) \
07873 MEMBER(member, membername, AST_DATA_STRING) \
07874 MEMBER(member, penalty, AST_DATA_INTEGER) \
07875 MEMBER(member, calls, AST_DATA_INTEGER) \
07876 MEMBER(member, dynamic, AST_DATA_INTEGER) \
07877 MEMBER(member, realtime, AST_DATA_INTEGER) \
07878 MEMBER(member, status, AST_DATA_INTEGER) \
07879 MEMBER(member, paused, AST_DATA_BOOLEAN) \
07880 MEMBER(member, rt_uniqueid, AST_DATA_STRING)
07881
07882 AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER);
07883
07884 #define DATA_EXPORT_QUEUE_ENT(MEMBER) \
07885 MEMBER(queue_ent, moh, AST_DATA_STRING) \
07886 MEMBER(queue_ent, announce, AST_DATA_STRING) \
07887 MEMBER(queue_ent, context, AST_DATA_STRING) \
07888 MEMBER(queue_ent, digits, AST_DATA_STRING) \
07889 MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER) \
07890 MEMBER(queue_ent, pos, AST_DATA_INTEGER) \
07891 MEMBER(queue_ent, prio, AST_DATA_INTEGER) \
07892 MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER) \
07893 MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER) \
07894 MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \
07895 MEMBER(queue_ent, last_pos, AST_DATA_INTEGER) \
07896 MEMBER(queue_ent, opos, AST_DATA_INTEGER) \
07897 MEMBER(queue_ent, handled, AST_DATA_INTEGER) \
07898 MEMBER(queue_ent, pending, AST_DATA_INTEGER) \
07899 MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER) \
07900 MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER) \
07901 MEMBER(queue_ent, linpos, AST_DATA_INTEGER) \
07902 MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER) \
07903 MEMBER(queue_ent, start, AST_DATA_INTEGER) \
07904 MEMBER(queue_ent, expire, AST_DATA_INTEGER) \
07905 MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER)
07906
07907 AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT);
07908
07909
07910
07911
07912
07913
07914
07915
07916 static void queues_data_provider_get_helper(const struct ast_data_search *search,
07917 struct ast_data *data_root, struct call_queue *queue)
07918 {
07919 struct ao2_iterator im;
07920 struct member *member;
07921 struct queue_ent *qe;
07922 struct ast_data *data_queue, *data_members = NULL, *enum_node;
07923 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
07924
07925 data_queue = ast_data_add_node(data_root, "queue");
07926 if (!data_queue) {
07927 return;
07928 }
07929
07930 ast_data_add_structure(call_queue, data_queue, queue);
07931
07932 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
07933
07934
07935 enum_node = ast_data_add_node(data_queue, "announceposition");
07936 if (!enum_node) {
07937 return;
07938 }
07939 switch (queue->announceposition) {
07940 case ANNOUNCEPOSITION_LIMIT:
07941 ast_data_add_str(enum_node, "text", "limit");
07942 break;
07943 case ANNOUNCEPOSITION_MORE_THAN:
07944 ast_data_add_str(enum_node, "text", "more");
07945 break;
07946 case ANNOUNCEPOSITION_YES:
07947 ast_data_add_str(enum_node, "text", "yes");
07948 break;
07949 case ANNOUNCEPOSITION_NO:
07950 ast_data_add_str(enum_node, "text", "no");
07951 break;
07952 default:
07953 ast_data_add_str(enum_node, "text", "unknown");
07954 break;
07955 }
07956 ast_data_add_int(enum_node, "value", queue->announceposition);
07957
07958
07959 im = ao2_iterator_init(queue->members, 0);
07960 while ((member = ao2_iterator_next(&im))) {
07961 if (!data_members) {
07962 data_members = ast_data_add_node(data_queue, "members");
07963 if (!data_members) {
07964 ao2_ref(member, -1);
07965 continue;
07966 }
07967 }
07968
07969 data_member = ast_data_add_node(data_members, "member");
07970 if (!data_member) {
07971 ao2_ref(member, -1);
07972 continue;
07973 }
07974
07975 ast_data_add_structure(member, data_member, member);
07976
07977 ao2_ref(member, -1);
07978 }
07979
07980
07981 if (queue->head) {
07982 for (qe = queue->head; qe; qe = qe->next) {
07983 if (!data_callers) {
07984 data_callers = ast_data_add_node(data_queue, "callers");
07985 if (!data_callers) {
07986 continue;
07987 }
07988 }
07989
07990 data_caller = ast_data_add_node(data_callers, "caller");
07991 if (!data_caller) {
07992 continue;
07993 }
07994
07995 ast_data_add_structure(queue_ent, data_caller, qe);
07996
07997
07998 data_caller_channel = ast_data_add_node(data_caller, "channel");
07999 if (!data_caller_channel) {
08000 continue;
08001 }
08002
08003 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
08004 }
08005 }
08006
08007
08008 if (!ast_data_search_match(search, data_queue)) {
08009 ast_data_remove_node(data_root, data_queue);
08010 }
08011 }
08012
08013
08014
08015
08016
08017
08018
08019
08020 static int queues_data_provider_get(const struct ast_data_search *search,
08021 struct ast_data *data_root)
08022 {
08023 struct ao2_iterator i;
08024 struct call_queue *queue, *queue_realtime = NULL;
08025 struct ast_config *cfg;
08026 char *queuename;
08027
08028
08029 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
08030 if (cfg) {
08031 for (queuename = ast_category_browse(cfg, NULL);
08032 !ast_strlen_zero(queuename);
08033 queuename = ast_category_browse(cfg, queuename)) {
08034 if ((queue = load_realtime_queue(queuename))) {
08035 queue_unref(queue);
08036 }
08037 }
08038 ast_config_destroy(cfg);
08039 }
08040
08041
08042 i = ao2_iterator_init(queues, 0);
08043 while ((queue = ao2_iterator_next(&i))) {
08044 ao2_lock(queue);
08045 if (queue->realtime && !(queue_realtime = load_realtime_queue(queue->name))) {
08046 ao2_unlock(queue);
08047 queue_unref(queue);
08048 continue;
08049 } else if (queue->realtime) {
08050 queue_unref(queue_realtime);
08051 }
08052
08053 queues_data_provider_get_helper(search, data_root, queue);
08054 ao2_unlock(queue);
08055 queue_unref(queue);
08056 }
08057
08058 return 0;
08059 }
08060
08061 static const struct ast_data_handler queues_data_provider = {
08062 .version = AST_DATA_HANDLER_VERSION,
08063 .get = queues_data_provider_get
08064 };
08065
08066 static const struct ast_data_entry queue_data_providers[] = {
08067 AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
08068 };
08069
08070 static int unload_module(void)
08071 {
08072 int res;
08073 struct ast_context *con;
08074 struct ao2_iterator q_iter;
08075 struct call_queue *q = NULL;
08076
08077 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
08078 res = ast_manager_unregister("QueueStatus");
08079 res |= ast_manager_unregister("Queues");
08080 res |= ast_manager_unregister("QueueRule");
08081 res |= ast_manager_unregister("QueueSummary");
08082 res |= ast_manager_unregister("QueueAdd");
08083 res |= ast_manager_unregister("QueueRemove");
08084 res |= ast_manager_unregister("QueuePause");
08085 res |= ast_manager_unregister("QueueLog");
08086 res |= ast_manager_unregister("QueuePenalty");
08087 res |= ast_unregister_application(app_aqm);
08088 res |= ast_unregister_application(app_rqm);
08089 res |= ast_unregister_application(app_pqm);
08090 res |= ast_unregister_application(app_upqm);
08091 res |= ast_unregister_application(app_ql);
08092 res |= ast_unregister_application(app);
08093 res |= ast_custom_function_unregister(&queueexists_function);
08094 res |= ast_custom_function_unregister(&queuevar_function);
08095 res |= ast_custom_function_unregister(&queuemembercount_function);
08096 res |= ast_custom_function_unregister(&queuemembercount_dep);
08097 res |= ast_custom_function_unregister(&queuememberlist_function);
08098 res |= ast_custom_function_unregister(&queuewaitingcount_function);
08099 res |= ast_custom_function_unregister(&queuememberpenalty_function);
08100
08101 res |= ast_data_unregister(NULL);
08102
08103 if (device_state_sub)
08104 ast_event_unsubscribe(device_state_sub);
08105
08106 ast_extension_state_del(0, extension_state_cb);
08107
08108 if ((con = ast_context_find("app_queue_gosub_virtual_context"))) {
08109 ast_context_remove_extension2(con, "s", 1, NULL, 0);
08110 ast_context_destroy(con, "app_queue");
08111 }
08112
08113 q_iter = ao2_iterator_init(queues, 0);
08114 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
08115 queues_t_unlink(queues, q, "Remove queue from container due to unload");
08116 queue_t_unref(q, "Done with iterator");
08117 }
08118 ao2_iterator_destroy(&q_iter);
08119 ao2_ref(queues, -1);
08120 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
08121 ast_unload_realtime("queue_members");
08122 return res;
08123 }
08124
08125 static int load_module(void)
08126 {
08127 int res;
08128 struct ast_context *con;
08129 struct ast_flags mask = {AST_FLAGS_ALL, };
08130
08131 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
08132
08133 use_weight = 0;
08134
08135 if (reload_handler(0, &mask, NULL))
08136 return AST_MODULE_LOAD_DECLINE;
08137
08138 con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
08139 if (!con)
08140 ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
08141 else
08142 ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
08143
08144 if (queue_persistent_members)
08145 reload_queue_members();
08146
08147 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
08148
08149 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
08150 res = ast_register_application_xml(app, queue_exec);
08151 res |= ast_register_application_xml(app_aqm, aqm_exec);
08152 res |= ast_register_application_xml(app_rqm, rqm_exec);
08153 res |= ast_register_application_xml(app_pqm, pqm_exec);
08154 res |= ast_register_application_xml(app_upqm, upqm_exec);
08155 res |= ast_register_application_xml(app_ql, ql_exec);
08156 res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
08157 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
08158 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
08159 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
08160 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
08161 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
08162 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
08163 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
08164 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
08165 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
08166 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
08167 res |= ast_custom_function_register(&queuevar_function);
08168 res |= ast_custom_function_register(&queueexists_function);
08169 res |= ast_custom_function_register(&queuemembercount_function);
08170 res |= ast_custom_function_register(&queuemembercount_dep);
08171 res |= ast_custom_function_register(&queuememberlist_function);
08172 res |= ast_custom_function_register(&queuewaitingcount_function);
08173 res |= ast_custom_function_register(&queuememberpenalty_function);
08174
08175 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
08176 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
08177 }
08178
08179
08180 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
08181 res = -1;
08182 }
08183
08184 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
08185
08186 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
08187
08188 return res ? AST_MODULE_LOAD_DECLINE : 0;
08189 }
08190
08191 static int reload(void)
08192 {
08193 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
08194 ast_unload_realtime("queue_members");
08195 reload_handler(1, &mask, NULL);
08196 return 0;
08197 }
08198
08199 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
08200 .load = load_module,
08201 .unload = unload_module,
08202 .reload = reload,
08203 .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
08204 .nonoptreq = "res_monitor",
08205 );
08206