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
00064 #include "asterisk.h"
00065
00066 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 415835 $")
00067
00068 #include <sys/time.h>
00069 #include <sys/signal.h>
00070 #include <netinet/in.h>
00071 #include <ctype.h>
00072
00073 #include "asterisk/lock.h"
00074 #include "asterisk/file.h"
00075 #include "asterisk/channel.h"
00076 #include "asterisk/pbx.h"
00077 #include "asterisk/app.h"
00078 #include "asterisk/linkedlists.h"
00079 #include "asterisk/module.h"
00080 #include "asterisk/translate.h"
00081 #include "asterisk/say.h"
00082 #include "asterisk/features.h"
00083 #include "asterisk/musiconhold.h"
00084 #include "asterisk/cli.h"
00085 #include "asterisk/manager.h"
00086 #include "asterisk/config.h"
00087 #include "asterisk/monitor.h"
00088 #include "asterisk/utils.h"
00089 #include "asterisk/causes.h"
00090 #include "asterisk/astdb.h"
00091 #include "asterisk/devicestate.h"
00092 #include "asterisk/stringfields.h"
00093 #include "asterisk/event.h"
00094 #include "asterisk/astobj2.h"
00095 #include "asterisk/strings.h"
00096 #include "asterisk/global_datastores.h"
00097 #include "asterisk/taskprocessor.h"
00098 #include "asterisk/aoc.h"
00099 #include "asterisk/callerid.h"
00100 #include "asterisk/cel.h"
00101 #include "asterisk/data.h"
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
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 enum {
00939 OPT_MARK_AS_ANSWERED = (1 << 0),
00940 OPT_GO_ON = (1 << 1),
00941 OPT_DATA_QUALITY = (1 << 2),
00942 OPT_CALLEE_GO_ON = (1 << 3),
00943 OPT_CALLEE_HANGUP = (1 << 4),
00944 OPT_CALLER_HANGUP = (1 << 5),
00945 OPT_IGNORE_CALL_FW = (1 << 6),
00946 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
00947 OPT_CALLEE_PARK = (1 << 8),
00948 OPT_CALLER_PARK = (1 << 9),
00949 OPT_NO_RETRY = (1 << 10),
00950 OPT_RINGING = (1 << 11),
00951 OPT_RING_WHEN_RINGING = (1 << 12),
00952 OPT_CALLEE_TRANSFER = (1 << 13),
00953 OPT_CALLER_TRANSFER = (1 << 14),
00954 OPT_CALLEE_AUTOMIXMON = (1 << 15),
00955 OPT_CALLER_AUTOMIXMON = (1 << 16),
00956 OPT_CALLEE_AUTOMON = (1 << 17),
00957 OPT_CALLER_AUTOMON = (1 << 18),
00958 };
00959
00960 enum {
00961 OPT_ARG_CALLEE_GO_ON = 0,
00962
00963 OPT_ARG_ARRAY_SIZE
00964 };
00965
00966 AST_APP_OPTIONS(queue_exec_options, BEGIN_OPTIONS
00967 AST_APP_OPTION('C', OPT_MARK_AS_ANSWERED),
00968 AST_APP_OPTION('c', OPT_GO_ON),
00969 AST_APP_OPTION('d', OPT_DATA_QUALITY),
00970 AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
00971 AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
00972 AST_APP_OPTION('H', OPT_CALLER_HANGUP),
00973 AST_APP_OPTION('i', OPT_IGNORE_CALL_FW),
00974 AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
00975 AST_APP_OPTION('k', OPT_CALLEE_PARK),
00976 AST_APP_OPTION('K', OPT_CALLER_PARK),
00977 AST_APP_OPTION('n', OPT_NO_RETRY),
00978 AST_APP_OPTION('r', OPT_RINGING),
00979 AST_APP_OPTION('R', OPT_RING_WHEN_RINGING),
00980 AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
00981 AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
00982 AST_APP_OPTION('x', OPT_CALLEE_AUTOMIXMON),
00983 AST_APP_OPTION('X', OPT_CALLER_AUTOMIXMON),
00984 AST_APP_OPTION('w', OPT_CALLEE_AUTOMON),
00985 AST_APP_OPTION('W', OPT_CALLER_AUTOMON),
00986 END_OPTIONS);
00987
00988 enum {
00989 QUEUE_STRATEGY_RINGALL = 0,
00990 QUEUE_STRATEGY_LEASTRECENT,
00991 QUEUE_STRATEGY_FEWESTCALLS,
00992 QUEUE_STRATEGY_RANDOM,
00993 QUEUE_STRATEGY_RRMEMORY,
00994 QUEUE_STRATEGY_LINEAR,
00995 QUEUE_STRATEGY_WRANDOM,
00996 QUEUE_STRATEGY_RRORDERED,
00997 };
00998
00999 enum {
01000 QUEUE_AUTOPAUSE_OFF = 0,
01001 QUEUE_AUTOPAUSE_ON,
01002 QUEUE_AUTOPAUSE_ALL
01003 };
01004
01005 enum queue_reload_mask {
01006 QUEUE_RELOAD_PARAMETERS = (1 << 0),
01007 QUEUE_RELOAD_MEMBER = (1 << 1),
01008 QUEUE_RELOAD_RULES = (1 << 2),
01009 QUEUE_RESET_STATS = (1 << 3),
01010 };
01011
01012 static const struct strategy {
01013 int strategy;
01014 const char *name;
01015 } strategies[] = {
01016 { QUEUE_STRATEGY_RINGALL, "ringall" },
01017 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
01018 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
01019 { QUEUE_STRATEGY_RANDOM, "random" },
01020 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
01021 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
01022 { QUEUE_STRATEGY_LINEAR, "linear" },
01023 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
01024 { QUEUE_STRATEGY_RRORDERED, "rrordered"},
01025 };
01026
01027 static const struct autopause {
01028 int autopause;
01029 const char *name;
01030 } autopausesmodes [] = {
01031 { QUEUE_AUTOPAUSE_OFF,"no" },
01032 { QUEUE_AUTOPAUSE_ON, "yes" },
01033 { QUEUE_AUTOPAUSE_ALL,"all" },
01034 };
01035
01036
01037 static struct ast_taskprocessor *devicestate_tps;
01038
01039 #define DEFAULT_RETRY 5
01040 #define DEFAULT_TIMEOUT 15
01041 #define RECHECK 1
01042 #define MAX_PERIODIC_ANNOUNCEMENTS 10
01043 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
01044
01045 #define MAX_QUEUE_BUCKETS 53
01046
01047 #define RES_OKAY 0
01048 #define RES_EXISTS (-1)
01049 #define RES_OUTOFMEMORY (-2)
01050 #define RES_NOSUCHQUEUE (-3)
01051 #define RES_NOT_DYNAMIC (-4)
01052
01053 static char *app = "Queue";
01054
01055 static char *app_aqm = "AddQueueMember" ;
01056
01057 static char *app_rqm = "RemoveQueueMember" ;
01058
01059 static char *app_pqm = "PauseQueueMember" ;
01060
01061 static char *app_upqm = "UnpauseQueueMember" ;
01062
01063 static char *app_ql = "QueueLog" ;
01064
01065
01066 static const char * const pm_family = "Queue/PersistentMembers";
01067
01068
01069 static int queue_persistent_members = 0;
01070
01071
01072 static int use_weight = 0;
01073
01074
01075 static int autofill_default = 1;
01076
01077
01078 static int montype_default = 0;
01079
01080
01081 static int shared_lastcall = 1;
01082
01083
01084 static struct ast_event_sub *device_state_sub;
01085
01086
01087 static int update_cdr = 0;
01088
01089
01090 static int negative_penalty_invalid = 0;
01091
01092
01093 static int log_membername_as_agent = 0;
01094
01095
01096 static char *realtime_ringinuse_field;
01097
01098 enum queue_result {
01099 QUEUE_UNKNOWN = 0,
01100 QUEUE_TIMEOUT = 1,
01101 QUEUE_JOINEMPTY = 2,
01102 QUEUE_LEAVEEMPTY = 3,
01103 QUEUE_JOINUNAVAIL = 4,
01104 QUEUE_LEAVEUNAVAIL = 5,
01105 QUEUE_FULL = 6,
01106 QUEUE_CONTINUE = 7,
01107 };
01108
01109 static const struct {
01110 enum queue_result id;
01111 char *text;
01112 } queue_results[] = {
01113 { QUEUE_UNKNOWN, "UNKNOWN" },
01114 { QUEUE_TIMEOUT, "TIMEOUT" },
01115 { QUEUE_JOINEMPTY,"JOINEMPTY" },
01116 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
01117 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
01118 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
01119 { QUEUE_FULL, "FULL" },
01120 { QUEUE_CONTINUE, "CONTINUE" },
01121 };
01122
01123 enum queue_timeout_priority {
01124 TIMEOUT_PRIORITY_APP,
01125 TIMEOUT_PRIORITY_CONF,
01126 };
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140 struct callattempt {
01141 struct callattempt *q_next;
01142 struct callattempt *call_next;
01143 struct ast_channel *chan;
01144 char interface[256];
01145 int metric;
01146 time_t lastcall;
01147 struct call_queue *lastqueue;
01148 struct member *member;
01149
01150 struct ast_party_connected_line connected;
01151
01152 unsigned int pending_connected_update:1;
01153
01154 unsigned int block_connected_update:1;
01155
01156 unsigned int dial_callerid_absent:1;
01157
01158 unsigned int stillgoing:1;
01159 struct ast_aoc_decoded *aoc_s_rate_list;
01160 };
01161
01162
01163 struct queue_ent {
01164 struct call_queue *parent;
01165 char moh[MAX_MUSICCLASS];
01166 char announce[PATH_MAX];
01167 char context[AST_MAX_CONTEXT];
01168 char digits[AST_MAX_EXTENSION];
01169 int valid_digits;
01170 int pos;
01171 int prio;
01172 int last_pos_said;
01173 int ring_when_ringing;
01174 time_t last_periodic_announce_time;
01175 int last_periodic_announce_sound;
01176 time_t last_pos;
01177 int opos;
01178 int handled;
01179 int pending;
01180 int max_penalty;
01181 int min_penalty;
01182 int linpos;
01183 int linwrapped;
01184 time_t start;
01185 time_t expire;
01186 int cancel_answered_elsewhere;
01187 struct ast_channel *chan;
01188 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules;
01189 struct penalty_rule *pr;
01190 struct queue_ent *next;
01191 };
01192
01193 struct member {
01194 char interface[AST_CHANNEL_NAME];
01195 char state_exten[AST_MAX_EXTENSION];
01196 char state_context[AST_MAX_CONTEXT];
01197 char state_interface[AST_CHANNEL_NAME];
01198 char membername[80];
01199 int penalty;
01200 int calls;
01201 int dynamic;
01202 int realtime;
01203 int status;
01204 int paused;
01205 int queuepos;
01206 time_t lastcall;
01207 struct call_queue *lastqueue;
01208 unsigned int dead:1;
01209 unsigned int delme:1;
01210 unsigned int call_pending:1;
01211 char rt_uniqueid[80];
01212 unsigned int ringinuse:1;
01213 };
01214
01215 enum empty_conditions {
01216 QUEUE_EMPTY_PENALTY = (1 << 0),
01217 QUEUE_EMPTY_PAUSED = (1 << 1),
01218 QUEUE_EMPTY_INUSE = (1 << 2),
01219 QUEUE_EMPTY_RINGING = (1 << 3),
01220 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
01221 QUEUE_EMPTY_INVALID = (1 << 5),
01222 QUEUE_EMPTY_UNKNOWN = (1 << 6),
01223 QUEUE_EMPTY_WRAPUP = (1 << 7),
01224 };
01225
01226 enum member_properties {
01227 MEMBER_PENALTY = 0,
01228 MEMBER_RINGINUSE = 1,
01229 };
01230
01231
01232 #define ANNOUNCEHOLDTIME_ALWAYS 1
01233 #define ANNOUNCEHOLDTIME_ONCE 2
01234 #define QUEUE_EVENT_VARIABLES 3
01235
01236 struct penalty_rule {
01237 int time;
01238 int max_value;
01239 int min_value;
01240 int max_relative;
01241 int min_relative;
01242 AST_LIST_ENTRY(penalty_rule) list;
01243 };
01244
01245 #define ANNOUNCEPOSITION_YES 1
01246 #define ANNOUNCEPOSITION_NO 2
01247 #define ANNOUNCEPOSITION_MORE_THAN 3
01248 #define ANNOUNCEPOSITION_LIMIT 4
01249
01250 struct call_queue {
01251 AST_DECLARE_STRING_FIELDS(
01252
01253 AST_STRING_FIELD(name);
01254
01255 AST_STRING_FIELD(moh);
01256
01257 AST_STRING_FIELD(announce);
01258
01259 AST_STRING_FIELD(context);
01260
01261 AST_STRING_FIELD(membermacro);
01262
01263 AST_STRING_FIELD(membergosub);
01264
01265 AST_STRING_FIELD(defaultrule);
01266
01267 AST_STRING_FIELD(sound_next);
01268
01269 AST_STRING_FIELD(sound_thereare);
01270
01271 AST_STRING_FIELD(sound_calls);
01272
01273 AST_STRING_FIELD(queue_quantity1);
01274
01275 AST_STRING_FIELD(queue_quantity2);
01276
01277 AST_STRING_FIELD(sound_holdtime);
01278
01279 AST_STRING_FIELD(sound_minutes);
01280
01281 AST_STRING_FIELD(sound_minute);
01282
01283 AST_STRING_FIELD(sound_seconds);
01284
01285 AST_STRING_FIELD(sound_thanks);
01286
01287 AST_STRING_FIELD(sound_callerannounce);
01288
01289 AST_STRING_FIELD(sound_reporthold);
01290 );
01291
01292 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
01293 unsigned int dead:1;
01294 unsigned int eventwhencalled:2;
01295 unsigned int ringinuse:1;
01296 unsigned int announce_to_first_user:1;
01297 unsigned int setinterfacevar:1;
01298 unsigned int setqueuevar:1;
01299 unsigned int setqueueentryvar:1;
01300 unsigned int reportholdtime:1;
01301 unsigned int wrapped:1;
01302 unsigned int timeoutrestart:1;
01303 unsigned int announceholdtime:2;
01304 unsigned int announceposition:3;
01305 int strategy:4;
01306 unsigned int maskmemberstatus:1;
01307 unsigned int realtime:1;
01308 unsigned int found:1;
01309 unsigned int relativeperiodicannounce:1;
01310 unsigned int autopausebusy:1;
01311 unsigned int autopauseunavail:1;
01312 enum empty_conditions joinempty;
01313 enum empty_conditions leavewhenempty;
01314 int announcepositionlimit;
01315 int announcefrequency;
01316 int minannouncefrequency;
01317 int periodicannouncefrequency;
01318 int numperiodicannounce;
01319 int randomperiodicannounce;
01320 int roundingseconds;
01321 int holdtime;
01322 int talktime;
01323 int callscompleted;
01324 int callsabandoned;
01325 int servicelevel;
01326 int callscompletedinsl;
01327 char monfmt[8];
01328 int montype;
01329 int count;
01330 int maxlen;
01331 int wrapuptime;
01332 int penaltymemberslimit;
01333
01334 int retry;
01335 int timeout;
01336 int weight;
01337 int autopause;
01338 int autopausedelay;
01339 int timeoutpriority;
01340
01341
01342 int rrpos;
01343 int memberdelay;
01344 int autofill;
01345
01346 struct ao2_container *members;
01347 struct queue_ent *head;
01348 AST_LIST_ENTRY(call_queue) list;
01349 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules;
01350 };
01351
01352 struct rule_list {
01353 char name[80];
01354 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
01355 AST_LIST_ENTRY(rule_list) list;
01356 };
01357
01358 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
01359
01360 static struct ao2_container *queues;
01361
01362 static void update_realtime_members(struct call_queue *q);
01363 static struct member *interface_exists(struct call_queue *q, const char *interface);
01364 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
01365
01366 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
01367
01368 static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
01369
01370 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
01371 {
01372 int i;
01373
01374 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
01375 if (queue_results[i].id == res) {
01376 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
01377 return;
01378 }
01379 }
01380 }
01381
01382 static const char *int2strat(int strategy)
01383 {
01384 int x;
01385
01386 for (x = 0; x < ARRAY_LEN(strategies); x++) {
01387 if (strategy == strategies[x].strategy) {
01388 return strategies[x].name;
01389 }
01390 }
01391
01392 return "<unknown>";
01393 }
01394
01395 static int strat2int(const char *strategy)
01396 {
01397 int x;
01398
01399 for (x = 0; x < ARRAY_LEN(strategies); x++) {
01400 if (!strcasecmp(strategy, strategies[x].name)) {
01401 return strategies[x].strategy;
01402 }
01403 }
01404
01405 return -1;
01406 }
01407
01408 static int autopause2int(const char *autopause)
01409 {
01410 int x;
01411
01412 if (ast_strlen_zero(autopause)) {
01413 return QUEUE_AUTOPAUSE_OFF;
01414 }
01415
01416
01417 if(ast_true(autopause)) {
01418 return QUEUE_AUTOPAUSE_ON;
01419 }
01420
01421 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
01422 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
01423 return autopausesmodes[x].autopause;
01424 }
01425 }
01426
01427
01428 return QUEUE_AUTOPAUSE_OFF;
01429 }
01430
01431 static int queue_hash_cb(const void *obj, const int flags)
01432 {
01433 const struct call_queue *q = obj;
01434
01435 return ast_str_case_hash(q->name);
01436 }
01437
01438 static int queue_cmp_cb(void *obj, void *arg, int flags)
01439 {
01440 struct call_queue *q = obj, *q2 = arg;
01441 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
01442 }
01443
01444
01445
01446
01447
01448
01449 static int queue_member_decrement_followers(void *obj, void *arg, int flag)
01450 {
01451 struct member *mem = obj;
01452 int *decrement_followers_after = arg;
01453
01454 if (mem->queuepos > *decrement_followers_after) {
01455 mem->queuepos--;
01456 }
01457
01458 return 0;
01459 }
01460
01461
01462
01463
01464
01465
01466
01467 static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
01468 {
01469 struct member *mem = obj;
01470 struct call_queue *queue = arg;
01471 int rrpos = mem->queuepos;
01472
01473 if (mem->delme) {
01474 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &rrpos);
01475 }
01476
01477 return 0;
01478 }
01479
01480
01481
01482
01483
01484
01485 static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
01486 {
01487 int pos = mem->queuepos;
01488
01489
01490
01491 if (pos < queue->rrpos) {
01492 queue->rrpos--;
01493 }
01494
01495 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos);
01496 }
01497
01498 #ifdef REF_DEBUG_ONLY_QUEUES
01499 #define queue_ref(q) _queue_ref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
01500 #define queue_unref(q) _queue_unref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
01501 #define queue_t_ref(q, tag) _queue_ref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01502 #define queue_t_unref(q, tag) _queue_unref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01503 #define queues_t_link(c, q, tag) __ao2_link_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01504 #define queues_t_unlink(c, q, tag) __ao2_unlink_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
01505
01506 static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
01507 {
01508 __ao2_ref_debug(q, 1, tag, file, line, filename);
01509 return q;
01510 }
01511
01512 static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
01513 {
01514 __ao2_ref_debug(q, -1, tag, file, line, filename);
01515 return NULL;
01516 }
01517
01518 #else
01519
01520 #define queue_t_ref(q, tag) queue_ref(q)
01521 #define queue_t_unref(q, tag) queue_unref(q)
01522 #define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
01523 #define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
01524
01525 static inline struct call_queue *queue_ref(struct call_queue *q)
01526 {
01527 ao2_ref(q, 1);
01528 return q;
01529 }
01530
01531 static inline struct call_queue *queue_unref(struct call_queue *q)
01532 {
01533 ao2_ref(q, -1);
01534 return NULL;
01535 }
01536 #endif
01537
01538
01539 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
01540 {
01541 char interfacevar[256]="";
01542 float sl = 0;
01543
01544 ao2_lock(q);
01545
01546 if (q->setqueuevar) {
01547 sl = 0;
01548 if (q->callscompleted > 0) {
01549 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
01550 }
01551
01552 snprintf(interfacevar, sizeof(interfacevar),
01553 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
01554 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
01555
01556 ao2_unlock(q);
01557
01558 pbx_builtin_setvar_multiple(chan, interfacevar);
01559 } else {
01560 ao2_unlock(q);
01561 }
01562 }
01563
01564
01565 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
01566 {
01567 struct queue_ent *cur;
01568
01569 if (!q || !new)
01570 return;
01571 if (prev) {
01572 cur = prev->next;
01573 prev->next = new;
01574 } else {
01575 cur = q->head;
01576 q->head = new;
01577 }
01578 new->next = cur;
01579
01580
01581
01582
01583 queue_ref(q);
01584 new->parent = q;
01585 new->pos = ++(*pos);
01586 new->opos = *pos;
01587 }
01588
01589
01590
01591
01592
01593
01594
01595 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
01596 {
01597 struct member *member;
01598 struct ao2_iterator mem_iter;
01599
01600 ao2_lock(q);
01601 mem_iter = ao2_iterator_init(q->members, 0);
01602 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
01603 if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) {
01604 if (conditions & QUEUE_EMPTY_PENALTY) {
01605 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
01606 continue;
01607 }
01608 }
01609
01610 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
01611 case AST_DEVICE_INVALID:
01612 if (conditions & QUEUE_EMPTY_INVALID) {
01613 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
01614 break;
01615 }
01616 goto default_case;
01617 case AST_DEVICE_UNAVAILABLE:
01618 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
01619 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
01620 break;
01621 }
01622 goto default_case;
01623 case AST_DEVICE_INUSE:
01624 if (conditions & QUEUE_EMPTY_INUSE) {
01625 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
01626 break;
01627 }
01628 goto default_case;
01629 case AST_DEVICE_RINGING:
01630 if (conditions & QUEUE_EMPTY_RINGING) {
01631 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
01632 break;
01633 }
01634 goto default_case;
01635 case AST_DEVICE_UNKNOWN:
01636 if (conditions & QUEUE_EMPTY_UNKNOWN) {
01637 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
01638 break;
01639 }
01640
01641 default:
01642 default_case:
01643 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
01644 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
01645 break;
01646 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
01647 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);
01648 break;
01649 } else {
01650 ao2_ref(member, -1);
01651 ao2_iterator_destroy(&mem_iter);
01652 ao2_unlock(q);
01653 ast_debug(4, "%s is available.\n", member->membername);
01654 return 0;
01655 }
01656 break;
01657 }
01658 }
01659 ao2_iterator_destroy(&mem_iter);
01660 ao2_unlock(q);
01661
01662 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
01663
01664 return get_member_status(q, max_penalty, min_penalty, conditions, 1);
01665 }
01666 return -1;
01667 }
01668
01669 struct statechange {
01670 AST_LIST_ENTRY(statechange) entry;
01671 int state;
01672 char dev[0];
01673 };
01674
01675
01676
01677
01678
01679
01680 static int update_status(struct call_queue *q, struct member *m, const int status)
01681 {
01682 m->status = status;
01683
01684 if (q->maskmemberstatus) {
01685 return 0;
01686 }
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01744 "Queue: %s\r\n"
01745 "Location: %s\r\n"
01746 "MemberName: %s\r\n"
01747 "StateInterface: %s\r\n"
01748 "Membership: %s\r\n"
01749 "Penalty: %d\r\n"
01750 "CallsTaken: %d\r\n"
01751 "LastCall: %d\r\n"
01752 "Status: %d\r\n"
01753 "Paused: %d\r\n",
01754 q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
01755 m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
01756 );
01757
01758 return 0;
01759 }
01760
01761
01762
01763
01764
01765
01766 static int is_member_available(struct call_queue *q, struct member *mem)
01767 {
01768 int available = 0;
01769
01770 switch (mem->status) {
01771 case AST_DEVICE_INVALID:
01772 case AST_DEVICE_UNAVAILABLE:
01773 break;
01774 case AST_DEVICE_INUSE:
01775 case AST_DEVICE_BUSY:
01776 case AST_DEVICE_RINGING:
01777 case AST_DEVICE_RINGINUSE:
01778 case AST_DEVICE_ONHOLD:
01779 if (!mem->ringinuse) {
01780 break;
01781 }
01782
01783 case AST_DEVICE_NOT_INUSE:
01784 case AST_DEVICE_UNKNOWN:
01785 if (!mem->paused) {
01786 available = 1;
01787 }
01788 break;
01789 }
01790
01791
01792 if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) {
01793 available = 0;
01794 }
01795 return available;
01796 }
01797
01798
01799 static int handle_statechange(void *datap)
01800 {
01801 struct statechange *sc = datap;
01802 struct ao2_iterator miter, qiter;
01803 struct member *m;
01804 struct call_queue *q;
01805 char interface[80], *slash_pos;
01806 int found = 0;
01807 int found_member;
01808 int avail = 0;
01809
01810 qiter = ao2_iterator_init(queues, 0);
01811 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
01812 ao2_lock(q);
01813
01814 avail = 0;
01815 found_member = 0;
01816 miter = ao2_iterator_init(q->members, 0);
01817 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01818 if (!found_member) {
01819 ast_copy_string(interface, m->state_interface, sizeof(interface));
01820
01821 if ((slash_pos = strchr(interface, '/'))) {
01822 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
01823 *slash_pos = '\0';
01824 }
01825 }
01826
01827 if (!strcasecmp(interface, sc->dev)) {
01828 found_member = 1;
01829 update_status(q, m, sc->state);
01830 }
01831 }
01832
01833
01834 if (!avail) {
01835 avail = is_member_available(q, m);
01836 }
01837 if (avail && found_member) {
01838
01839 ao2_ref(m, -1);
01840 break;
01841 }
01842 }
01843
01844 if (found_member) {
01845 found = 1;
01846 if (avail) {
01847 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
01848 } else {
01849 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
01850 }
01851 }
01852
01853 ao2_iterator_destroy(&miter);
01854
01855 ao2_unlock(q);
01856 queue_t_unref(q, "Done with iterator");
01857 }
01858 ao2_iterator_destroy(&qiter);
01859
01860 if (found) {
01861 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01862 } else {
01863 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));
01864 }
01865
01866 ast_free(sc);
01867 return 0;
01868 }
01869
01870 static void device_state_cb(const struct ast_event *event, void *unused)
01871 {
01872 enum ast_device_state state;
01873 const char *device;
01874 struct statechange *sc;
01875 size_t datapsize;
01876
01877 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01878 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
01879
01880 if (ast_strlen_zero(device)) {
01881 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
01882 return;
01883 }
01884 datapsize = sizeof(*sc) + strlen(device) + 1;
01885 if (!(sc = ast_calloc(1, datapsize))) {
01886 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
01887 return;
01888 }
01889 sc->state = state;
01890 strcpy(sc->dev, device);
01891 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
01892 ast_free(sc);
01893 }
01894 }
01895
01896
01897 static int extensionstate2devicestate(int state)
01898 {
01899 switch (state) {
01900 case AST_EXTENSION_NOT_INUSE:
01901 state = AST_DEVICE_NOT_INUSE;
01902 break;
01903 case AST_EXTENSION_INUSE:
01904 state = AST_DEVICE_INUSE;
01905 break;
01906 case AST_EXTENSION_BUSY:
01907 state = AST_DEVICE_BUSY;
01908 break;
01909 case AST_EXTENSION_RINGING:
01910 state = AST_DEVICE_RINGING;
01911 break;
01912 case AST_EXTENSION_ONHOLD:
01913 state = AST_DEVICE_ONHOLD;
01914 break;
01915 case AST_EXTENSION_UNAVAILABLE:
01916 state = AST_DEVICE_UNAVAILABLE;
01917 break;
01918 case AST_EXTENSION_REMOVED:
01919 case AST_EXTENSION_DEACTIVATED:
01920 default:
01921 state = AST_DEVICE_INVALID;
01922 break;
01923 }
01924
01925 return state;
01926 }
01927
01928 static int extension_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
01929 {
01930 struct ao2_iterator miter, qiter;
01931 struct member *m;
01932 struct call_queue *q;
01933 int state = info->exten_state;
01934 int found = 0, device_state = extensionstate2devicestate(state);
01935
01936
01937 if (info->reason != AST_HINT_UPDATE_DEVICE) {
01938 return 0;
01939 }
01940
01941 qiter = ao2_iterator_init(queues, 0);
01942 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
01943 ao2_lock(q);
01944
01945 miter = ao2_iterator_init(q->members, 0);
01946 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01947 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
01948 update_status(q, m, device_state);
01949 ao2_ref(m, -1);
01950 found = 1;
01951 break;
01952 }
01953 }
01954 ao2_iterator_destroy(&miter);
01955
01956 ao2_unlock(q);
01957 queue_t_unref(q, "Done with iterator");
01958 }
01959 ao2_iterator_destroy(&qiter);
01960
01961 if (found) {
01962 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
01963 } else {
01964 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",
01965 exten, context, device_state, ast_devstate2str(device_state));
01966 }
01967
01968 return 0;
01969 }
01970
01971
01972 static int get_queue_member_status(struct member *cur)
01973 {
01974 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
01975 }
01976
01977
01978 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse)
01979 {
01980 struct member *cur;
01981
01982 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
01983 cur->ringinuse = ringinuse;
01984 cur->penalty = penalty;
01985 cur->paused = paused;
01986 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
01987 if (!ast_strlen_zero(state_interface)) {
01988 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
01989 } else {
01990 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
01991 }
01992 if (!ast_strlen_zero(membername)) {
01993 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
01994 } else {
01995 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
01996 }
01997 if (!strchr(cur->interface, '/')) {
01998 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
01999 }
02000 if (!strncmp(cur->state_interface, "hint:", 5)) {
02001 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
02002 char *exten = strsep(&context, "@") + 5;
02003
02004 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
02005 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
02006 }
02007 cur->status = get_queue_member_status(cur);
02008 }
02009
02010 return cur;
02011 }
02012
02013
02014 static int compress_char(const char c)
02015 {
02016 if (c < 32) {
02017 return 0;
02018 } else if (c > 96) {
02019 return c - 64;
02020 }
02021 return c - 32;
02022 }
02023
02024 static int member_hash_fn(const void *obj, const int flags)
02025 {
02026 const struct member *mem = obj;
02027 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
02028 const char *chname = strchr(interface, '/');
02029 int ret = 0, i;
02030
02031 if (!chname) {
02032 chname = interface;
02033 }
02034 for (i = 0; i < 5 && chname[i]; i++) {
02035 ret += compress_char(chname[i]) << (i * 6);
02036 }
02037 return ret;
02038 }
02039
02040 static int member_cmp_fn(void *obj1, void *obj2, int flags)
02041 {
02042 struct member *mem1 = obj1;
02043 struct member *mem2 = obj2;
02044 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
02045
02046 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
02047 }
02048
02049
02050
02051
02052
02053 static void init_queue(struct call_queue *q)
02054 {
02055 int i;
02056 struct penalty_rule *pr_iter;
02057
02058 q->dead = 0;
02059 q->retry = DEFAULT_RETRY;
02060 q->timeout = DEFAULT_TIMEOUT;
02061 q->maxlen = 0;
02062 q->announcefrequency = 0;
02063 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
02064 q->announceholdtime = 1;
02065 q->announcepositionlimit = 10;
02066 q->announceposition = ANNOUNCEPOSITION_YES;
02067 q->roundingseconds = 0;
02068 q->servicelevel = 0;
02069 q->ringinuse = 1;
02070 q->announce_to_first_user = 0;
02071 q->setinterfacevar = 0;
02072 q->setqueuevar = 0;
02073 q->setqueueentryvar = 0;
02074 q->autofill = autofill_default;
02075 q->montype = montype_default;
02076 q->monfmt[0] = '\0';
02077 q->reportholdtime = 0;
02078 q->wrapuptime = 0;
02079 q->penaltymemberslimit = 0;
02080 q->joinempty = 0;
02081 q->leavewhenempty = 0;
02082 q->memberdelay = 0;
02083 q->maskmemberstatus = 0;
02084 q->eventwhencalled = 0;
02085 q->weight = 0;
02086 q->timeoutrestart = 0;
02087 q->periodicannouncefrequency = 0;
02088 q->randomperiodicannounce = 0;
02089 q->numperiodicannounce = 0;
02090 q->autopause = QUEUE_AUTOPAUSE_OFF;
02091 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
02092 q->autopausedelay = 0;
02093 if (!q->members) {
02094 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) {
02095
02096 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
02097 } else {
02098 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
02099 }
02100 }
02101 q->found = 1;
02102
02103 ast_string_field_set(q, sound_next, "queue-youarenext");
02104 ast_string_field_set(q, sound_thereare, "queue-thereare");
02105 ast_string_field_set(q, sound_calls, "queue-callswaiting");
02106 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
02107 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
02108 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
02109 ast_string_field_set(q, sound_minutes, "queue-minutes");
02110 ast_string_field_set(q, sound_minute, "queue-minute");
02111 ast_string_field_set(q, sound_seconds, "queue-seconds");
02112 ast_string_field_set(q, sound_thanks, "queue-thankyou");
02113 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
02114
02115 if (!q->sound_periodicannounce[0]) {
02116 q->sound_periodicannounce[0] = ast_str_create(32);
02117 }
02118
02119 if (q->sound_periodicannounce[0]) {
02120 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
02121 }
02122
02123 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
02124 if (q->sound_periodicannounce[i]) {
02125 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
02126 }
02127 }
02128
02129 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
02130 ast_free(pr_iter);
02131 }
02132
02133
02134
02135
02136
02137
02138
02139
02140 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
02141 }
02142
02143 static void clear_queue(struct call_queue *q)
02144 {
02145 q->holdtime = 0;
02146 q->callscompleted = 0;
02147 q->callsabandoned = 0;
02148 q->callscompletedinsl = 0;
02149 q->talktime = 0;
02150
02151 if (q->members) {
02152 struct member *mem;
02153 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
02154 while ((mem = ao2_iterator_next(&mem_iter))) {
02155 mem->calls = 0;
02156 mem->lastcall = 0;
02157 ao2_ref(mem, -1);
02158 }
02159 ao2_iterator_destroy(&mem_iter);
02160 }
02161 }
02162
02163
02164
02165
02166
02167
02168
02169
02170
02171
02172 static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
02173 {
02174 char *timestr, *maxstr, *minstr, *contentdup;
02175 struct penalty_rule *rule = NULL, *rule_iter;
02176 struct rule_list *rl_iter;
02177 int penaltychangetime, inserted = 0;
02178
02179 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
02180 return -1;
02181 }
02182
02183 contentdup = ast_strdupa(content);
02184
02185 if (!(maxstr = strchr(contentdup, ','))) {
02186 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
02187 ast_free(rule);
02188 return -1;
02189 }
02190
02191 *maxstr++ = '\0';
02192 timestr = contentdup;
02193
02194 if ((penaltychangetime = atoi(timestr)) < 0) {
02195 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
02196 ast_free(rule);
02197 return -1;
02198 }
02199
02200 rule->time = penaltychangetime;
02201
02202 if ((minstr = strchr(maxstr,','))) {
02203 *minstr++ = '\0';
02204 }
02205
02206
02207
02208 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
02209 rule->max_relative = 1;
02210 }
02211
02212 rule->max_value = atoi(maxstr);
02213
02214 if (!ast_strlen_zero(minstr)) {
02215 if (*minstr == '+' || *minstr == '-') {
02216 rule->min_relative = 1;
02217 }
02218 rule->min_value = atoi(minstr);
02219 } else {
02220 rule->min_relative = 1;
02221 }
02222
02223
02224 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
02225 if (strcasecmp(rl_iter->name, list_name)) {
02226 continue;
02227 }
02228
02229 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
02230 if (rule->time < rule_iter->time) {
02231 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
02232 inserted = 1;
02233 break;
02234 }
02235 }
02236 AST_LIST_TRAVERSE_SAFE_END;
02237
02238 if (!inserted) {
02239 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
02240 inserted = 1;
02241 }
02242
02243 break;
02244 }
02245
02246 if (!inserted) {
02247 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
02248 ast_free(rule);
02249 return -1;
02250 }
02251 return 0;
02252 }
02253
02254 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
02255 {
02256 char *value_copy = ast_strdupa(value);
02257 char *option = NULL;
02258 while ((option = strsep(&value_copy, ","))) {
02259 if (!strcasecmp(option, "paused")) {
02260 *empty |= QUEUE_EMPTY_PAUSED;
02261 } else if (!strcasecmp(option, "penalty")) {
02262 *empty |= QUEUE_EMPTY_PENALTY;
02263 } else if (!strcasecmp(option, "inuse")) {
02264 *empty |= QUEUE_EMPTY_INUSE;
02265 } else if (!strcasecmp(option, "ringing")) {
02266 *empty |= QUEUE_EMPTY_RINGING;
02267 } else if (!strcasecmp(option, "invalid")) {
02268 *empty |= QUEUE_EMPTY_INVALID;
02269 } else if (!strcasecmp(option, "wrapup")) {
02270 *empty |= QUEUE_EMPTY_WRAPUP;
02271 } else if (!strcasecmp(option, "unavailable")) {
02272 *empty |= QUEUE_EMPTY_UNAVAILABLE;
02273 } else if (!strcasecmp(option, "unknown")) {
02274 *empty |= QUEUE_EMPTY_UNKNOWN;
02275 } else if (!strcasecmp(option, "loose")) {
02276 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
02277 } else if (!strcasecmp(option, "strict")) {
02278 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
02279 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
02280 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
02281 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
02282 *empty = 0;
02283 } else {
02284 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
02285 }
02286 }
02287 }
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
02298 {
02299 if (!strcasecmp(param, "musicclass") ||
02300 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
02301 ast_string_field_set(q, moh, val);
02302 } else if (!strcasecmp(param, "announce")) {
02303 ast_string_field_set(q, announce, val);
02304 } else if (!strcasecmp(param, "context")) {
02305 ast_string_field_set(q, context, val);
02306 } else if (!strcasecmp(param, "timeout")) {
02307 q->timeout = atoi(val);
02308 if (q->timeout < 0) {
02309 q->timeout = DEFAULT_TIMEOUT;
02310 }
02311 } else if (!strcasecmp(param, "ringinuse")) {
02312 q->ringinuse = ast_true(val);
02313 } else if (!strcasecmp(param, "setinterfacevar")) {
02314 q->setinterfacevar = ast_true(val);
02315 } else if (!strcasecmp(param, "setqueuevar")) {
02316 q->setqueuevar = ast_true(val);
02317 } else if (!strcasecmp(param, "setqueueentryvar")) {
02318 q->setqueueentryvar = ast_true(val);
02319 } else if (!strcasecmp(param, "monitor-format")) {
02320 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
02321 } else if (!strcasecmp(param, "membermacro")) {
02322 ast_string_field_set(q, membermacro, val);
02323 } else if (!strcasecmp(param, "membergosub")) {
02324 ast_string_field_set(q, membergosub, val);
02325 } else if (!strcasecmp(param, "queue-youarenext")) {
02326 ast_string_field_set(q, sound_next, val);
02327 } else if (!strcasecmp(param, "queue-thereare")) {
02328 ast_string_field_set(q, sound_thereare, val);
02329 } else if (!strcasecmp(param, "queue-callswaiting")) {
02330 ast_string_field_set(q, sound_calls, val);
02331 } else if (!strcasecmp(param, "queue-quantity1")) {
02332 ast_string_field_set(q, queue_quantity1, val);
02333 } else if (!strcasecmp(param, "queue-quantity2")) {
02334 ast_string_field_set(q, queue_quantity2, val);
02335 } else if (!strcasecmp(param, "queue-holdtime")) {
02336 ast_string_field_set(q, sound_holdtime, val);
02337 } else if (!strcasecmp(param, "queue-minutes")) {
02338 ast_string_field_set(q, sound_minutes, val);
02339 } else if (!strcasecmp(param, "queue-minute")) {
02340 ast_string_field_set(q, sound_minute, val);
02341 } else if (!strcasecmp(param, "queue-seconds")) {
02342 ast_string_field_set(q, sound_seconds, val);
02343 } else if (!strcasecmp(param, "queue-thankyou")) {
02344 ast_string_field_set(q, sound_thanks, val);
02345 } else if (!strcasecmp(param, "queue-callerannounce")) {
02346 ast_string_field_set(q, sound_callerannounce, val);
02347 } else if (!strcasecmp(param, "queue-reporthold")) {
02348 ast_string_field_set(q, sound_reporthold, val);
02349 } else if (!strcasecmp(param, "announce-frequency")) {
02350 q->announcefrequency = atoi(val);
02351 } else if (!strcasecmp(param, "announce-to-first-user")) {
02352 q->announce_to_first_user = ast_true(val);
02353 } else if (!strcasecmp(param, "min-announce-frequency")) {
02354 q->minannouncefrequency = atoi(val);
02355 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
02356 } else if (!strcasecmp(param, "announce-round-seconds")) {
02357 q->roundingseconds = atoi(val);
02358
02359 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
02360 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
02361 if (linenum >= 0) {
02362 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
02363 "using 0 instead for queue '%s' at line %d of queues.conf\n",
02364 val, param, q->name, linenum);
02365 } else {
02366 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
02367 "using 0 instead for queue '%s'\n", val, param, q->name);
02368 }
02369 q->roundingseconds=0;
02370 }
02371 } else if (!strcasecmp(param, "announce-holdtime")) {
02372 if (!strcasecmp(val, "once")) {
02373 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
02374 } else if (ast_true(val)) {
02375 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
02376 } else {
02377 q->announceholdtime = 0;
02378 }
02379 } else if (!strcasecmp(param, "announce-position")) {
02380 if (!strcasecmp(val, "limit")) {
02381 q->announceposition = ANNOUNCEPOSITION_LIMIT;
02382 } else if (!strcasecmp(val, "more")) {
02383 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
02384 } else if (ast_true(val)) {
02385 q->announceposition = ANNOUNCEPOSITION_YES;
02386 } else {
02387 q->announceposition = ANNOUNCEPOSITION_NO;
02388 }
02389 } else if (!strcasecmp(param, "announce-position-limit")) {
02390 q->announcepositionlimit = atoi(val);
02391 } else if (!strcasecmp(param, "periodic-announce")) {
02392 if (strchr(val, ',')) {
02393 char *s, *buf = ast_strdupa(val);
02394 unsigned int i = 0;
02395
02396 while ((s = strsep(&buf, ",|"))) {
02397 if (!q->sound_periodicannounce[i]) {
02398 q->sound_periodicannounce[i] = ast_str_create(16);
02399 }
02400 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
02401 i++;
02402 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
02403 break;
02404 }
02405 }
02406 q->numperiodicannounce = i;
02407 } else {
02408 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
02409 q->numperiodicannounce = 1;
02410 }
02411 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
02412 q->periodicannouncefrequency = atoi(val);
02413 } else if (!strcasecmp(param, "relative-periodic-announce")) {
02414 q->relativeperiodicannounce = ast_true(val);
02415 } else if (!strcasecmp(param, "random-periodic-announce")) {
02416 q->randomperiodicannounce = ast_true(val);
02417 } else if (!strcasecmp(param, "retry")) {
02418 q->retry = atoi(val);
02419 if (q->retry <= 0) {
02420 q->retry = DEFAULT_RETRY;
02421 }
02422 } else if (!strcasecmp(param, "wrapuptime")) {
02423 q->wrapuptime = atoi(val);
02424 } else if (!strcasecmp(param, "penaltymemberslimit")) {
02425 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
02426 q->penaltymemberslimit = 0;
02427 }
02428 } else if (!strcasecmp(param, "autofill")) {
02429 q->autofill = ast_true(val);
02430 } else if (!strcasecmp(param, "monitor-type")) {
02431 if (!strcasecmp(val, "mixmonitor")) {
02432 q->montype = 1;
02433 }
02434 } else if (!strcasecmp(param, "autopause")) {
02435 q->autopause = autopause2int(val);
02436 } else if (!strcasecmp(param, "autopausedelay")) {
02437 q->autopausedelay = atoi(val);
02438 } else if (!strcasecmp(param, "autopausebusy")) {
02439 q->autopausebusy = ast_true(val);
02440 } else if (!strcasecmp(param, "autopauseunavail")) {
02441 q->autopauseunavail = ast_true(val);
02442 } else if (!strcasecmp(param, "maxlen")) {
02443 q->maxlen = atoi(val);
02444 if (q->maxlen < 0) {
02445 q->maxlen = 0;
02446 }
02447 } else if (!strcasecmp(param, "servicelevel")) {
02448 q->servicelevel= atoi(val);
02449 } else if (!strcasecmp(param, "strategy")) {
02450 int strategy;
02451
02452
02453 if (failunknown) {
02454 return;
02455 }
02456 strategy = strat2int(val);
02457 if (strategy < 0) {
02458 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02459 val, q->name);
02460 q->strategy = QUEUE_STRATEGY_RINGALL;
02461 }
02462 if (strategy == q->strategy) {
02463 return;
02464 }
02465 if (strategy == QUEUE_STRATEGY_LINEAR) {
02466 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
02467 return;
02468 }
02469 q->strategy = strategy;
02470 } else if (!strcasecmp(param, "joinempty")) {
02471 parse_empty_options(val, &q->joinempty, 1);
02472 } else if (!strcasecmp(param, "leavewhenempty")) {
02473 parse_empty_options(val, &q->leavewhenempty, 0);
02474 } else if (!strcasecmp(param, "eventmemberstatus")) {
02475 q->maskmemberstatus = !ast_true(val);
02476 } else if (!strcasecmp(param, "eventwhencalled")) {
02477 if (!strcasecmp(val, "vars")) {
02478 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
02479 } else {
02480 q->eventwhencalled = ast_true(val) ? 1 : 0;
02481 }
02482 } else if (!strcasecmp(param, "reportholdtime")) {
02483 q->reportholdtime = ast_true(val);
02484 } else if (!strcasecmp(param, "memberdelay")) {
02485 q->memberdelay = atoi(val);
02486 } else if (!strcasecmp(param, "weight")) {
02487 q->weight = atoi(val);
02488 } else if (!strcasecmp(param, "timeoutrestart")) {
02489 q->timeoutrestart = ast_true(val);
02490 } else if (!strcasecmp(param, "defaultrule")) {
02491 ast_string_field_set(q, defaultrule, val);
02492 } else if (!strcasecmp(param, "timeoutpriority")) {
02493 if (!strcasecmp(val, "conf")) {
02494 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
02495 } else {
02496 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
02497 }
02498 } else if (failunknown) {
02499 if (linenum >= 0) {
02500 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
02501 q->name, param, linenum);
02502 } else {
02503 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
02504 }
02505 }
02506 }
02507
02508
02509
02510
02511
02512
02513
02514 static void member_add_to_queue(struct call_queue *queue, struct member *mem)
02515 {
02516 ao2_lock(queue->members);
02517 mem->queuepos = ao2_container_count(queue->members);
02518 ao2_link(queue->members, mem);
02519 ao2_unlock(queue->members);
02520 }
02521
02522
02523
02524
02525
02526
02527
02528 static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
02529 {
02530 ao2_lock(queue->members);
02531 queue_member_follower_removal(queue, mem);
02532 ao2_unlink(queue->members, mem);
02533 ao2_unlock(queue->members);
02534 }
02535
02536
02537
02538
02539
02540
02541
02542 static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
02543 {
02544 struct member *m;
02545 struct ao2_iterator mem_iter;
02546 int penalty = 0;
02547 int paused = 0;
02548 int found = 0;
02549 int ringinuse = q->ringinuse;
02550
02551 const char *config_val;
02552 const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
02553 const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
02554 const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
02555 const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty");
02556 const char *paused_str = ast_variable_retrieve(member_config, interface, "paused");
02557
02558 if (ast_strlen_zero(rt_uniqueid)) {
02559 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
02560 return;
02561 }
02562
02563 if (penalty_str) {
02564 penalty = atoi(penalty_str);
02565 if ((penalty < 0) && negative_penalty_invalid) {
02566 return;
02567 } else if (penalty < 0) {
02568 penalty = 0;
02569 }
02570 }
02571
02572 if (paused_str) {
02573 paused = atoi(paused_str);
02574 if (paused < 0) {
02575 paused = 0;
02576 }
02577 }
02578
02579 if ((config_val = ast_variable_retrieve(member_config, interface, realtime_ringinuse_field))) {
02580 if (ast_true(config_val)) {
02581 ringinuse = 1;
02582 } else if (ast_false(config_val)) {
02583 ringinuse = 0;
02584 } else {
02585 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
02586 }
02587 }
02588
02589
02590 mem_iter = ao2_iterator_init(q->members, 0);
02591 while ((m = ao2_iterator_next(&mem_iter))) {
02592 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
02593 m->dead = 0;
02594 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
02595 if (paused_str) {
02596 m->paused = paused;
02597 }
02598 if (strcasecmp(state_interface, m->state_interface)) {
02599 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
02600 }
02601 m->penalty = penalty;
02602 m->ringinuse = ringinuse;
02603 found = 1;
02604 ao2_ref(m, -1);
02605 break;
02606 }
02607 ao2_ref(m, -1);
02608 }
02609 ao2_iterator_destroy(&mem_iter);
02610
02611
02612 if (!found) {
02613 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse))) {
02614 m->dead = 0;
02615 m->realtime = 1;
02616 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
02617 if (!log_membername_as_agent) {
02618 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
02619 } else {
02620 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
02621 }
02622 member_add_to_queue(q, m);
02623 ao2_ref(m, -1);
02624 m = NULL;
02625 }
02626 }
02627 }
02628
02629
02630 static void free_members(struct call_queue *q, int all)
02631 {
02632
02633 struct member *cur;
02634 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
02635
02636 while ((cur = ao2_iterator_next(&mem_iter))) {
02637 if (all || !cur->dynamic) {
02638 member_remove_from_queue(q, cur);
02639 }
02640 ao2_ref(cur, -1);
02641 }
02642 ao2_iterator_destroy(&mem_iter);
02643 }
02644
02645
02646 static void destroy_queue(void *obj)
02647 {
02648 struct call_queue *q = obj;
02649 int i;
02650
02651 free_members(q, 1);
02652 ast_string_field_free_memory(q);
02653 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
02654 if (q->sound_periodicannounce[i]) {
02655 free(q->sound_periodicannounce[i]);
02656 }
02657 }
02658 ao2_ref(q->members, -1);
02659 }
02660
02661 static struct call_queue *alloc_queue(const char *queuename)
02662 {
02663 struct call_queue *q;
02664
02665 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
02666 if (ast_string_field_init(q, 64)) {
02667 queue_t_unref(q, "String field allocation failed");
02668 return NULL;
02669 }
02670 ast_string_field_set(q, name, queuename);
02671 }
02672 return q;
02673 }
02674
02675
02676
02677
02678
02679
02680
02681
02682
02683
02684
02685 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
02686 {
02687 struct ast_variable *v;
02688 struct call_queue *q, tmpq = {
02689 .name = queuename,
02690 };
02691 struct member *m;
02692 struct ao2_iterator mem_iter;
02693 char *interface = NULL;
02694 const char *tmp_name;
02695 char *tmp;
02696 char tmpbuf[64];
02697
02698
02699 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
02700 ao2_lock(q);
02701 if (!q->realtime) {
02702 if (q->dead) {
02703 ao2_unlock(q);
02704 queue_t_unref(q, "Queue is dead; can't return it");
02705 return NULL;
02706 }
02707 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
02708 ao2_unlock(q);
02709 return q;
02710 }
02711 } else if (!member_config) {
02712
02713 return NULL;
02714 }
02715
02716 if (!queue_vars) {
02717
02718 if (q) {
02719
02720
02721
02722 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
02723
02724 q->dead = 1;
02725
02726 queues_t_unlink(queues, q, "Unused; removing from container");
02727 ao2_unlock(q);
02728 queue_t_unref(q, "Queue is dead; can't return it");
02729 }
02730 return NULL;
02731 }
02732
02733
02734 if (!q) {
02735 struct ast_variable *tmpvar = NULL;
02736 if (!(q = alloc_queue(queuename))) {
02737 return NULL;
02738 }
02739 ao2_lock(q);
02740 clear_queue(q);
02741 q->realtime = 1;
02742
02743
02744
02745 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
02746 if (!strcasecmp(tmpvar->name, "strategy")) {
02747 q->strategy = strat2int(tmpvar->value);
02748 if (q->strategy < 0) {
02749 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02750 tmpvar->value, q->name);
02751 q->strategy = QUEUE_STRATEGY_RINGALL;
02752 }
02753 break;
02754 }
02755 }
02756
02757 if (!tmpvar) {
02758 q->strategy = QUEUE_STRATEGY_RINGALL;
02759 }
02760 queues_t_link(queues, q, "Add queue to container");
02761 }
02762 init_queue(q);
02763
02764 memset(tmpbuf, 0, sizeof(tmpbuf));
02765 for (v = queue_vars; v; v = v->next) {
02766
02767 if (strchr(v->name, '_')) {
02768 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
02769 tmp_name = tmpbuf;
02770 tmp = tmpbuf;
02771 while ((tmp = strchr(tmp, '_'))) {
02772 *tmp++ = '-';
02773 }
02774 } else {
02775 tmp_name = v->name;
02776 }
02777
02778
02779
02780
02781 queue_set_param(q, tmp_name, v->value, -1, 0);
02782 }
02783
02784
02785 mem_iter = ao2_iterator_init(q->members, 0);
02786 while ((m = ao2_iterator_next(&mem_iter))) {
02787 if (m->realtime) {
02788 m->dead = 1;
02789 }
02790 ao2_ref(m, -1);
02791 }
02792 ao2_iterator_destroy(&mem_iter);
02793
02794 while ((interface = ast_category_browse(member_config, interface))) {
02795 rt_handle_member_record(q, interface, member_config);
02796 }
02797
02798
02799 mem_iter = ao2_iterator_init(q->members, 0);
02800 while ((m = ao2_iterator_next(&mem_iter))) {
02801 if (m->dead) {
02802 if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
02803 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02804 } else {
02805 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
02806 }
02807 member_remove_from_queue(q, m);
02808 }
02809 ao2_ref(m, -1);
02810 }
02811 ao2_iterator_destroy(&mem_iter);
02812
02813 ao2_unlock(q);
02814
02815 return q;
02816 }
02817
02818
02819
02820
02821
02822
02823
02824
02825
02826
02827
02828
02829 static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
02830 {
02831 struct ast_variable *queue_vars;
02832 struct ast_config *member_config = NULL;
02833 struct call_queue *q = NULL, tmpq = {
02834 .name = queuename,
02835 };
02836 int prev_weight = 0;
02837
02838
02839 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
02840
02841 if (!q || q->realtime) {
02842
02843
02844
02845
02846
02847
02848
02849
02850
02851 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
02852 if (queue_vars) {
02853 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
02854 if (!member_config) {
02855 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
02856 member_config = ast_config_new();
02857 }
02858 }
02859 if (q) {
02860 prev_weight = q->weight ? 1 : 0;
02861 queue_t_unref(q, "Need to find realtime queue");
02862 }
02863
02864 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
02865 ast_config_destroy(member_config);
02866 ast_variables_destroy(queue_vars);
02867
02868
02869 if (q) {
02870 if (!q->weight && prev_weight) {
02871 ast_atomic_fetchadd_int(&use_weight, -1);
02872 }
02873 if (q->weight && !prev_weight) {
02874 ast_atomic_fetchadd_int(&use_weight, +1);
02875 }
02876 }
02877
02878 } else {
02879 update_realtime_members(q);
02880 }
02881 return q;
02882 }
02883
02884 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
02885 {
02886 int ret = -1;
02887
02888 if (ast_strlen_zero(mem->rt_uniqueid)) {
02889 return ret;
02890 }
02891
02892 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) {
02893 ret = 0;
02894 }
02895
02896 return ret;
02897 }
02898
02899
02900 static void update_realtime_members(struct call_queue *q)
02901 {
02902 struct ast_config *member_config = NULL;
02903 struct member *m;
02904 char *interface = NULL;
02905 struct ao2_iterator mem_iter;
02906
02907 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
02908
02909
02910
02911 ao2_lock(q);
02912 mem_iter = ao2_iterator_init(q->members, 0);
02913 while ((m = ao2_iterator_next(&mem_iter))) {
02914 if (m->realtime) {
02915 member_remove_from_queue(q, m);
02916 }
02917 ao2_ref(m, -1);
02918 }
02919 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
02920 ao2_unlock(q);
02921 return;
02922 }
02923
02924 ao2_lock(q);
02925
02926
02927 mem_iter = ao2_iterator_init(q->members, 0);
02928 while ((m = ao2_iterator_next(&mem_iter))) {
02929 if (m->realtime) {
02930 m->dead = 1;
02931 }
02932 ao2_ref(m, -1);
02933 }
02934 ao2_iterator_destroy(&mem_iter);
02935
02936 while ((interface = ast_category_browse(member_config, interface))) {
02937 rt_handle_member_record(q, interface, member_config);
02938 }
02939
02940
02941 mem_iter = ao2_iterator_init(q->members, 0);
02942 while ((m = ao2_iterator_next(&mem_iter))) {
02943 if (m->dead) {
02944 if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
02945 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02946 } else {
02947 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
02948 }
02949 member_remove_from_queue(q, m);
02950 }
02951 ao2_ref(m, -1);
02952 }
02953 ao2_iterator_destroy(&mem_iter);
02954 ao2_unlock(q);
02955 ast_config_destroy(member_config);
02956 }
02957
02958 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
02959 {
02960 struct call_queue *q;
02961 struct queue_ent *cur, *prev = NULL;
02962 int res = -1;
02963 int pos = 0;
02964 int inserted = 0;
02965
02966 if (!(q = find_load_queue_rt_friendly(queuename))) {
02967 return res;
02968 }
02969 ao2_lock(q);
02970
02971
02972 if (q->joinempty) {
02973 int status = 0;
02974 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty, 0))) {
02975 *reason = QUEUE_JOINEMPTY;
02976 ao2_unlock(q);
02977 queue_t_unref(q, "Done with realtime queue");
02978 return res;
02979 }
02980 }
02981 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
02982 *reason = QUEUE_FULL;
02983 } else if (*reason == QUEUE_UNKNOWN) {
02984
02985
02986
02987 inserted = 0;
02988 prev = NULL;
02989 cur = q->head;
02990 while (cur) {
02991
02992
02993
02994 if ((!inserted) && (qe->prio > cur->prio)) {
02995 insert_entry(q, prev, qe, &pos);
02996 inserted = 1;
02997 }
02998
02999
03000
03001 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
03002 insert_entry(q, prev, qe, &pos);
03003 inserted = 1;
03004
03005 if (position < pos) {
03006 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
03007 }
03008 }
03009 cur->pos = ++pos;
03010 prev = cur;
03011 cur = cur->next;
03012 }
03013
03014 if (!inserted) {
03015 insert_entry(q, prev, qe, &pos);
03016 }
03017 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
03018 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
03019 ast_copy_string(qe->context, q->context, sizeof(qe->context));
03020 q->count++;
03021 if (q->count == 1) {
03022 ast_devstate_changed(AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
03023 }
03024
03025 res = 0;
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
03045 "Channel: %s\r\n"
03046 "CallerIDNum: %s\r\n"
03047 "CallerIDName: %s\r\n"
03048 "ConnectedLineNum: %s\r\n"
03049 "ConnectedLineName: %s\r\n"
03050 "Queue: %s\r\n"
03051 "Position: %d\r\n"
03052 "Count: %d\r\n"
03053 "Uniqueid: %s\r\n",
03054 ast_channel_name(qe->chan),
03055 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
03056 S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
03057 S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
03058 S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
03059 q->name, qe->pos, q->count, ast_channel_uniqueid(qe->chan));
03060 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
03061 }
03062 ao2_unlock(q);
03063 queue_t_unref(q, "Done with realtime queue");
03064
03065 return res;
03066 }
03067
03068 static int play_file(struct ast_channel *chan, const char *filename)
03069 {
03070 int res;
03071
03072 if (ast_strlen_zero(filename)) {
03073 return 0;
03074 }
03075
03076 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
03077 return 0;
03078 }
03079
03080 ast_stopstream(chan);
03081
03082 res = ast_streamfile(chan, filename, ast_channel_language(chan));
03083 if (!res) {
03084 res = ast_waitstream(chan, AST_DIGIT_ANY);
03085 }
03086
03087 ast_stopstream(chan);
03088
03089 return res;
03090 }
03091
03092
03093
03094
03095
03096
03097 static int valid_exit(struct queue_ent *qe, char digit)
03098 {
03099 int digitlen = strlen(qe->digits);
03100
03101
03102 if (digitlen < sizeof(qe->digits) - 2) {
03103 qe->digits[digitlen] = digit;
03104 qe->digits[digitlen + 1] = '\0';
03105 } else {
03106 qe->digits[0] = '\0';
03107 return 0;
03108 }
03109
03110
03111 if (ast_strlen_zero(qe->context)) {
03112 return 0;
03113 }
03114
03115
03116 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
03117 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, NULL))) {
03118 qe->digits[0] = '\0';
03119 return 0;
03120 }
03121
03122
03123 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
03124 qe->valid_digits = 1;
03125
03126 return 1;
03127 }
03128
03129 return 0;
03130 }
03131
03132 static int say_position(struct queue_ent *qe, int ringing)
03133 {
03134 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
03135 int say_thanks = 1;
03136 time_t now;
03137
03138
03139 time(&now);
03140 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
03141 return 0;
03142 }
03143
03144
03145 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
03146 return 0;
03147 }
03148
03149 if (ringing) {
03150 ast_indicate(qe->chan,-1);
03151 } else {
03152 ast_moh_stop(qe->chan);
03153 }
03154
03155 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
03156 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
03157 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
03158 qe->pos <= qe->parent->announcepositionlimit)) {
03159 announceposition = 1;
03160 }
03161
03162
03163 if (announceposition == 1) {
03164
03165 if (qe->pos == 1) {
03166 res = play_file(qe->chan, qe->parent->sound_next);
03167 if (res) {
03168 goto playout;
03169 }
03170 goto posout;
03171 } else {
03172 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
03173
03174 res = play_file(qe->chan, qe->parent->queue_quantity1);
03175 if (res) {
03176 goto playout;
03177 }
03178 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
03179 if (res) {
03180 goto playout;
03181 }
03182 } else {
03183
03184 res = play_file(qe->chan, qe->parent->sound_thereare);
03185 if (res) {
03186 goto playout;
03187 }
03188 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
03189 if (res) {
03190 goto playout;
03191 }
03192 }
03193 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
03194
03195 res = play_file(qe->chan, qe->parent->queue_quantity2);
03196 if (res) {
03197 goto playout;
03198 }
03199 } else {
03200 res = play_file(qe->chan, qe->parent->sound_calls);
03201 if (res) {
03202 goto playout;
03203 }
03204 }
03205 }
03206 }
03207
03208 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
03209
03210
03211 if (qe->parent->roundingseconds) {
03212 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
03213 avgholdsecs *= qe->parent->roundingseconds;
03214 } else {
03215 avgholdsecs = 0;
03216 }
03217
03218 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
03219
03220
03221
03222 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
03223 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
03224 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
03225 res = play_file(qe->chan, qe->parent->sound_holdtime);
03226 if (res) {
03227 goto playout;
03228 }
03229
03230 if (avgholdmins >= 1) {
03231 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
03232 if (res) {
03233 goto playout;
03234 }
03235
03236 if (avgholdmins == 1) {
03237 res = play_file(qe->chan, qe->parent->sound_minute);
03238 if (res) {
03239 goto playout;
03240 }
03241 } else {
03242 res = play_file(qe->chan, qe->parent->sound_minutes);
03243 if (res) {
03244 goto playout;
03245 }
03246 }
03247 }
03248 if (avgholdsecs >= 1) {
03249 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
03250 if (res) {
03251 goto playout;
03252 }
03253
03254 res = play_file(qe->chan, qe->parent->sound_seconds);
03255 if (res) {
03256 goto playout;
03257 }
03258 }
03259 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
03260 say_thanks = 0;
03261 }
03262
03263 posout:
03264 if (qe->parent->announceposition) {
03265 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
03266 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
03267 }
03268 if (say_thanks) {
03269 res = play_file(qe->chan, qe->parent->sound_thanks);
03270 }
03271 playout:
03272
03273 if ((res > 0 && !valid_exit(qe, res))) {
03274 res = 0;
03275 }
03276
03277
03278 qe->last_pos = now;
03279 qe->last_pos_said = qe->pos;
03280
03281
03282 if (!res) {
03283 if (ringing) {
03284 ast_indicate(qe->chan, AST_CONTROL_RINGING);
03285 } else {
03286 ast_moh_start(qe->chan, qe->moh, NULL);
03287 }
03288 }
03289 return res;
03290 }
03291
03292 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
03293 {
03294 int oldvalue;
03295
03296
03297
03298
03299
03300 ao2_lock(qe->parent);
03301 oldvalue = qe->parent->holdtime;
03302 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
03303 ao2_unlock(qe->parent);
03304 }
03305
03306
03307
03308
03309
03310
03311 static void leave_queue(struct queue_ent *qe)
03312 {
03313 struct call_queue *q;
03314 struct queue_ent *current, *prev = NULL;
03315 struct penalty_rule *pr_iter;
03316 int pos = 0;
03317
03318 if (!(q = qe->parent)) {
03319 return;
03320 }
03321 queue_t_ref(q, "Copy queue pointer from queue entry");
03322 ao2_lock(q);
03323
03324 prev = NULL;
03325 for (current = q->head; current; current = current->next) {
03326 if (current == qe) {
03327 char posstr[20];
03328 q->count--;
03329 if (!q->count) {
03330 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
03331 }
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344
03345
03346
03347 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
03348 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
03349 ast_channel_name(qe->chan), q->name, q->count, qe->pos, ast_channel_uniqueid(qe->chan));
03350 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
03351
03352 if (prev) {
03353 prev->next = current->next;
03354 } else {
03355 q->head = current->next;
03356 }
03357
03358 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
03359 ast_free(pr_iter);
03360 }
03361 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
03362 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
03363 } else {
03364
03365 current->pos = ++pos;
03366 prev = current;
03367 }
03368 }
03369 ao2_unlock(q);
03370
03371
03372 if (q->realtime) {
03373 struct ast_variable *var;
03374 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
03375 q->dead = 1;
03376 } else {
03377 ast_variables_destroy(var);
03378 }
03379 }
03380
03381 if (q->dead) {
03382
03383 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
03384 }
03385
03386 queue_t_unref(q, "Expire copied reference");
03387 }
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397
03398 static void callattempt_free(struct callattempt *doomed)
03399 {
03400 if (doomed->member) {
03401 ao2_ref(doomed->member, -1);
03402 }
03403 ast_party_connected_line_free(&doomed->connected);
03404 ast_free(doomed);
03405 }
03406
03407
03408 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
03409 {
03410 struct callattempt *oo;
03411
03412 while (outgoing) {
03413
03414
03415 if (outgoing->chan && (outgoing->chan != exception)) {
03416 if (exception || cancel_answered_elsewhere) {
03417 ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
03418 }
03419 ast_hangup(outgoing->chan);
03420 }
03421 oo = outgoing;
03422 outgoing = outgoing->q_next;
03423 ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
03424 callattempt_free(oo);
03425 }
03426 }
03427
03428
03429
03430
03431
03432
03433
03434
03435
03436 static int num_available_members(struct call_queue *q)
03437 {
03438 struct member *mem;
03439 int avl = 0;
03440 struct ao2_iterator mem_iter;
03441
03442 mem_iter = ao2_iterator_init(q->members, 0);
03443 while ((mem = ao2_iterator_next(&mem_iter))) {
03444
03445 avl += is_member_available(q, mem);
03446 ao2_ref(mem, -1);
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
03459 break;
03460 }
03461 }
03462 ao2_iterator_destroy(&mem_iter);
03463
03464 return avl;
03465 }
03466
03467
03468
03469 static int compare_weight(struct call_queue *rq, struct member *member)
03470 {
03471 struct call_queue *q;
03472 struct member *mem;
03473 int found = 0;
03474 struct ao2_iterator queue_iter;
03475
03476 queue_iter = ao2_iterator_init(queues, 0);
03477 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
03478 if (q == rq) {
03479 queue_t_unref(q, "Done with iterator");
03480 continue;
03481 }
03482 ao2_lock(q);
03483 if (q->count && q->members) {
03484 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
03485 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
03486 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
03487 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);
03488 found = 1;
03489 }
03490 ao2_ref(mem, -1);
03491 }
03492 }
03493 ao2_unlock(q);
03494 queue_t_unref(q, "Done with iterator");
03495 if (found) {
03496 break;
03497 }
03498 }
03499 ao2_iterator_destroy(&queue_iter);
03500 return found;
03501 }
03502
03503
03504 static void do_hang(struct callattempt *o)
03505 {
03506 o->stillgoing = 0;
03507 ast_hangup(o->chan);
03508 o->chan = NULL;
03509 }
03510
03511
03512 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
03513 {
03514 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
03515 const char *tmp;
03516
03517 if (pbx_builtin_serialize_variables(chan, &buf)) {
03518 int i, j;
03519
03520
03521 strcpy(vars, "Variable: ");
03522 tmp = ast_str_buffer(buf);
03523
03524 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
03525 vars[j] = tmp[i];
03526
03527 if (tmp[i + 1] == '\0') {
03528 break;
03529 }
03530 if (tmp[i] == '\n') {
03531 vars[j++] = '\r';
03532 vars[j++] = '\n';
03533
03534 ast_copy_string(&(vars[j]), "Variable: ", len - j);
03535 j += 9;
03536 }
03537 }
03538 if (j > len - 3) {
03539 j = len - 3;
03540 }
03541 vars[j++] = '\r';
03542 vars[j++] = '\n';
03543 vars[j] = '\0';
03544 } else {
03545
03546 *vars = '\0';
03547 }
03548 return vars;
03549 }
03550
03551
03552
03553
03554
03555
03556
03557
03558
03559 static int member_status_available(int status)
03560 {
03561 return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN;
03562 }
03563
03564
03565
03566
03567
03568
03569
03570
03571
03572 static void member_call_pending_clear(struct member *mem)
03573 {
03574 ao2_lock(mem);
03575 mem->call_pending = 0;
03576 ao2_unlock(mem);
03577 }
03578
03579
03580
03581
03582
03583
03584
03585
03586
03587 static int member_call_pending_set(struct member *mem)
03588 {
03589 int old_pending;
03590
03591 ao2_lock(mem);
03592 old_pending = mem->call_pending;
03593 mem->call_pending = 1;
03594 ao2_unlock(mem);
03595
03596 return old_pending;
03597 }
03598
03599
03600
03601
03602
03603
03604
03605
03606
03607
03608 static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
03609 {
03610 if (call->member->paused) {
03611 ast_debug(1, "%s paused, can't receive call\n", call->interface);
03612 return 0;
03613 }
03614
03615 if (!call->member->ringinuse && !member_status_available(call->member->status)) {
03616 ast_debug(1, "%s not available, can't receive call\n", call->interface);
03617 return 0;
03618 }
03619
03620 if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime))
03621 || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) {
03622 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
03623 (call->lastqueue ? call->lastqueue->name : qe->parent->name),
03624 call->interface);
03625 return 0;
03626 }
03627
03628 if (use_weight && compare_weight(qe->parent, call->member)) {
03629 ast_debug(1, "Priority queue delaying call to %s:%s\n",
03630 qe->parent->name, call->interface);
03631 return 0;
03632 }
03633
03634 if (!call->member->ringinuse) {
03635 if (member_call_pending_set(call->member)) {
03636 ast_debug(1, "%s has another call pending, can't receive call\n",
03637 call->interface);
03638 return 0;
03639 }
03640
03641
03642
03643
03644
03645
03646 if (!member_status_available(get_queue_member_status(call->member))) {
03647 ast_debug(1, "%s actually not available, can't receive call\n",
03648 call->interface);
03649 member_call_pending_clear(call->member);
03650 return 0;
03651 }
03652 }
03653
03654 return 1;
03655 }
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667
03668
03669
03670
03671 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
03672 {
03673 int res;
03674 int status;
03675 char tech[256];
03676 char *location;
03677 const char *macrocontext, *macroexten;
03678
03679
03680 if (!can_ring_entry(qe, tmp)) {
03681 if (ast_channel_cdr(qe->chan)) {
03682 ast_cdr_busy(ast_channel_cdr(qe->chan));
03683 }
03684 tmp->stillgoing = 0;
03685 ++*busies;
03686 return 0;
03687 }
03688 ast_assert(tmp->member->ringinuse || tmp->member->call_pending);
03689
03690 ast_copy_string(tech, tmp->interface, sizeof(tech));
03691 if ((location = strchr(tech, '/'))) {
03692 *location++ = '\0';
03693 } else {
03694 location = "";
03695 }
03696
03697
03698 tmp->chan = ast_request(tech, ast_channel_nativeformats(qe->chan), qe->chan, location, &status);
03699 if (!tmp->chan) {
03700 ao2_lock(qe->parent);
03701 qe->parent->rrpos++;
03702 qe->linpos++;
03703 ao2_unlock(qe->parent);
03704
03705 member_call_pending_clear(tmp->member);
03706
03707 if (ast_channel_cdr(qe->chan)) {
03708 ast_cdr_busy(ast_channel_cdr(qe->chan));
03709 }
03710 tmp->stillgoing = 0;
03711 ++*busies;
03712 return 0;
03713 }
03714
03715 ast_channel_lock_both(tmp->chan, qe->chan);
03716
03717 if (qe->cancel_answered_elsewhere) {
03718 ast_channel_hangupcause_set(tmp->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
03719 }
03720 ast_channel_appl_set(tmp->chan, "AppQueue");
03721 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
03722 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
03723
03724
03725 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
03726 if (ast_channel_connected(qe->chan)->id.number.valid) {
03727 struct ast_party_caller caller;
03728
03729 ast_party_caller_set_init(&caller, ast_channel_caller(tmp->chan));
03730 caller.id = ast_channel_connected(qe->chan)->id;
03731 caller.ani = ast_channel_connected(qe->chan)->ani;
03732 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
03733 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
03734 ast_set_callerid(tmp->chan, ast_channel_dialed(qe->chan)->number.str, NULL, NULL);
03735 } else if (!ast_strlen_zero(S_OR(ast_channel_macroexten(qe->chan), ast_channel_exten(qe->chan)))) {
03736 ast_set_callerid(tmp->chan, S_OR(ast_channel_macroexten(qe->chan), ast_channel_exten(qe->chan)), NULL, NULL);
03737 }
03738 tmp->dial_callerid_absent = 1;
03739 }
03740
03741 ast_party_redirecting_copy(ast_channel_redirecting(tmp->chan), ast_channel_redirecting(qe->chan));
03742
03743 ast_channel_dialed(tmp->chan)->transit_network_select = ast_channel_dialed(qe->chan)->transit_network_select;
03744
03745 ast_connected_line_copy_from_caller(ast_channel_connected(tmp->chan), ast_channel_caller(qe->chan));
03746
03747
03748 ast_channel_inherit_variables(qe->chan, tmp->chan);
03749 ast_channel_datastore_inherit(qe->chan, tmp->chan);
03750
03751
03752 ast_channel_adsicpe_set(tmp->chan, ast_channel_adsicpe(qe->chan));
03753
03754
03755 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
03756 ast_channel_dialcontext_set(tmp->chan, ast_strlen_zero(macrocontext) ? ast_channel_context(qe->chan) : macrocontext);
03757 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
03758 if (!ast_strlen_zero(macroexten)) {
03759 ast_channel_exten_set(tmp->chan, macroexten);
03760 } else {
03761 ast_channel_exten_set(tmp->chan, ast_channel_exten(qe->chan));
03762 }
03763 if (ast_cdr_isset_unanswered()) {
03764
03765
03766 ast_cdr_setdestchan(ast_channel_cdr(tmp->chan), ast_channel_name(tmp->chan));
03767 strcpy(ast_channel_cdr(tmp->chan)->clid, ast_channel_cdr(qe->chan)->clid);
03768 strcpy(ast_channel_cdr(tmp->chan)->channel, ast_channel_cdr(qe->chan)->channel);
03769 strcpy(ast_channel_cdr(tmp->chan)->src, ast_channel_cdr(qe->chan)->src);
03770 strcpy(ast_channel_cdr(tmp->chan)->dst, ast_channel_exten(qe->chan));
03771 strcpy(ast_channel_cdr(tmp->chan)->dcontext, ast_channel_context(qe->chan));
03772 strcpy(ast_channel_cdr(tmp->chan)->lastapp, ast_channel_cdr(qe->chan)->lastapp);
03773 strcpy(ast_channel_cdr(tmp->chan)->lastdata, ast_channel_cdr(qe->chan)->lastdata);
03774 ast_channel_cdr(tmp->chan)->amaflags = ast_channel_cdr(qe->chan)->amaflags;
03775 strcpy(ast_channel_cdr(tmp->chan)->accountcode, ast_channel_cdr(qe->chan)->accountcode);
03776 strcpy(ast_channel_cdr(tmp->chan)->userfield, ast_channel_cdr(qe->chan)->userfield);
03777 }
03778
03779 ast_channel_unlock(tmp->chan);
03780 ast_channel_unlock(qe->chan);
03781
03782
03783 if ((res = ast_call(tmp->chan, location, 0))) {
03784
03785 ast_verb(3, "Couldn't call %s\n", tmp->interface);
03786 do_hang(tmp);
03787 member_call_pending_clear(tmp->member);
03788 ++*busies;
03789 return 0;
03790 }
03791
03792 if (qe->parent->eventwhencalled) {
03793 char vars[2048];
03794
03795 ast_channel_lock_both(tmp->chan, qe->chan);
03796
03797
03798
03799
03800
03801
03802
03803
03804
03805
03806
03807
03808
03809
03810
03811
03812
03813
03814
03815
03816
03817
03818
03819 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
03820 "Queue: %s\r\n"
03821 "AgentCalled: %s\r\n"
03822 "AgentName: %s\r\n"
03823 "ChannelCalling: %s\r\n"
03824 "DestinationChannel: %s\r\n"
03825 "CallerIDNum: %s\r\n"
03826 "CallerIDName: %s\r\n"
03827 "ConnectedLineNum: %s\r\n"
03828 "ConnectedLineName: %s\r\n"
03829 "Context: %s\r\n"
03830 "Extension: %s\r\n"
03831 "Priority: %d\r\n"
03832 "Uniqueid: %s\r\n"
03833 "%s",
03834 qe->parent->name, tmp->interface, tmp->member->membername, ast_channel_name(qe->chan), ast_channel_name(tmp->chan),
03835 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
03836 S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
03837 S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
03838 S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
03839 ast_channel_context(qe->chan), ast_channel_exten(qe->chan), ast_channel_priority(qe->chan), ast_channel_uniqueid(qe->chan),
03840 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03841
03842 ast_channel_unlock(tmp->chan);
03843 ast_channel_unlock(qe->chan);
03844
03845 ast_verb(3, "Called %s\n", tmp->interface);
03846 }
03847
03848 member_call_pending_clear(tmp->member);
03849 return 1;
03850 }
03851
03852
03853 static struct callattempt *find_best(struct callattempt *outgoing)
03854 {
03855 struct callattempt *best = NULL, *cur;
03856
03857 for (cur = outgoing; cur; cur = cur->q_next) {
03858 if (cur->stillgoing &&
03859 !cur->chan &&
03860 (!best || cur->metric < best->metric)) {
03861 best = cur;
03862 }
03863 }
03864
03865 return best;
03866 }
03867
03868
03869
03870
03871
03872
03873
03874
03875
03876
03877
03878 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
03879 {
03880 int ret = 0;
03881
03882 while (ret == 0) {
03883 struct callattempt *best = find_best(outgoing);
03884 if (!best) {
03885 ast_debug(1, "Nobody left to try ringing in queue\n");
03886 break;
03887 }
03888 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03889 struct callattempt *cur;
03890
03891 for (cur = outgoing; cur; cur = cur->q_next) {
03892 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
03893 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
03894 ret |= ring_entry(qe, cur, busies);
03895 }
03896 }
03897 } else {
03898
03899 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
03900 ret = ring_entry(qe, best, busies);
03901 }
03902
03903
03904 if (qe->expire && (time(NULL) >= qe->expire)) {
03905 ast_debug(1, "Queue timed out while ringing members.\n");
03906 ret = 0;
03907 break;
03908 }
03909 }
03910
03911 return ret;
03912 }
03913
03914
03915 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
03916 {
03917 struct callattempt *best = find_best(outgoing);
03918
03919 if (best) {
03920
03921 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03922 qe->parent->rrpos = best->metric % 1000;
03923 } else {
03924
03925 if (qe->parent->wrapped) {
03926
03927 qe->parent->rrpos = 0;
03928 } else {
03929
03930 qe->parent->rrpos++;
03931 }
03932 }
03933 qe->parent->wrapped = 0;
03934
03935 return 0;
03936 }
03937
03938
03939 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
03940 {
03941 struct callattempt *best = find_best(outgoing);
03942
03943 if (best) {
03944
03945 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03946 qe->linpos = best->metric % 1000;
03947 } else {
03948
03949 if (qe->linwrapped) {
03950
03951 qe->linpos = 0;
03952 } else {
03953
03954 qe->linpos++;
03955 }
03956 }
03957 qe->linwrapped = 0;
03958
03959 return 0;
03960 }
03961
03962
03963 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
03964 {
03965 int res = 0;
03966 time_t now;
03967
03968
03969 time(&now);
03970
03971
03972 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) {
03973 return 0;
03974 }
03975
03976
03977 if (ringing) {
03978 ast_indicate(qe->chan,-1);
03979 } else {
03980 ast_moh_stop(qe->chan);
03981 }
03982
03983 ast_verb(3, "Playing periodic announcement\n");
03984
03985 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
03986 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
03987 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
03988 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
03989 qe->last_periodic_announce_sound = 0;
03990 }
03991
03992
03993 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
03994
03995 if (res > 0 && !valid_exit(qe, res)) {
03996 res = 0;
03997 }
03998
03999
04000 if (!res) {
04001 if (ringing) {
04002 ast_indicate(qe->chan, AST_CONTROL_RINGING);
04003 } else {
04004 ast_moh_start(qe->chan, qe->moh, NULL);
04005 }
04006 }
04007
04008
04009 if (qe->parent->relativeperiodicannounce) {
04010 time(&qe->last_periodic_announce_time);
04011 } else {
04012 qe->last_periodic_announce_time = now;
04013 }
04014
04015
04016 if (!qe->parent->randomperiodicannounce) {
04017 qe->last_periodic_announce_sound++;
04018 }
04019
04020 return res;
04021 }
04022
04023
04024 static void record_abandoned(struct queue_ent *qe)
04025 {
04026 set_queue_variables(qe->parent, qe->chan);
04027 ao2_lock(qe->parent);
04028
04029
04030
04031
04032
04033
04034
04035
04036
04037
04038
04039
04040
04041
04042
04043 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
04044 "Queue: %s\r\n"
04045 "Uniqueid: %s\r\n"
04046 "Position: %d\r\n"
04047 "OriginalPosition: %d\r\n"
04048 "HoldTime: %d\r\n",
04049 qe->parent->name, ast_channel_uniqueid(qe->chan), qe->pos, qe->opos, (int)(time(NULL) - qe->start));
04050
04051 qe->parent->callsabandoned++;
04052 ao2_unlock(qe->parent);
04053 }
04054
04055
04056 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int autopause)
04057 {
04058 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
04059
04060
04061 if (qe->ring_when_ringing) {
04062 ast_indicate(qe->chan, -1);
04063 ast_moh_start(qe->chan, qe->moh, NULL);
04064 }
04065
04066 if (qe->parent->eventwhencalled) {
04067 char vars[2048];
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079
04080
04081
04082
04083
04084
04085
04086
04087 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
04088 "Queue: %s\r\n"
04089 "Uniqueid: %s\r\n"
04090 "Channel: %s\r\n"
04091 "Member: %s\r\n"
04092 "MemberName: %s\r\n"
04093 "RingTime: %d\r\n"
04094 "%s",
04095 qe->parent->name,
04096 ast_channel_uniqueid(qe->chan),
04097 ast_channel_name(qe->chan),
04098 interface,
04099 membername,
04100 rnatime,
04101 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
04102 }
04103 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
04104 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && autopause) {
04105 if (qe->parent->autopausedelay > 0) {
04106 struct member *mem;
04107 ao2_lock(qe->parent);
04108 if ((mem = interface_exists(qe->parent, interface))) {
04109 time_t idletime = time(&idletime)-mem->lastcall;
04110 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
04111 ao2_unlock(qe->parent);
04112 ao2_ref(mem, -1);
04113 return;
04114 }
04115 ao2_ref(mem, -1);
04116 }
04117 ao2_unlock(qe->parent);
04118 }
04119 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
04120 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
04121 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
04122 interface, qe->parent->name);
04123 } else {
04124 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
04125 }
04126 } else {
04127
04128
04129 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
04130 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
04131 interface, qe->parent->name);
04132 } else {
04133 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
04134 }
04135 }
04136 }
04137 return;
04138 }
04139
04140 #define AST_MAX_WATCHERS 256
04141
04142
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152
04153
04154 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 ringing)
04155 {
04156 const char *queue = qe->parent->name;
04157 struct callattempt *o, *start = NULL, *prev = NULL;
04158 int status;
04159 int numbusies = prebusies;
04160 int numnochan = 0;
04161 int stillgoing = 0;
04162 int orig = *to;
04163 struct ast_frame *f;
04164 struct callattempt *peer = NULL;
04165 struct ast_channel *winner;
04166 struct ast_channel *in = qe->chan;
04167 char on[80] = "";
04168 char membername[80] = "";
04169 long starttime = 0;
04170 long endtime = 0;
04171 #ifdef HAVE_EPOLL
04172 struct callattempt *epollo;
04173 #endif
04174 struct ast_party_connected_line connected_caller;
04175 char *inchan_name;
04176 struct timeval start_time_tv = ast_tvnow();
04177
04178 ast_party_connected_line_init(&connected_caller);
04179
04180 ast_channel_lock(qe->chan);
04181 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
04182 ast_channel_unlock(qe->chan);
04183
04184 starttime = (long) time(NULL);
04185 #ifdef HAVE_EPOLL
04186 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
04187 if (epollo->chan) {
04188 ast_poll_channel_add(in, epollo->chan);
04189 }
04190 }
04191 #endif
04192
04193 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
04194 int numlines, retry, pos = 1;
04195 struct ast_channel *watchers[AST_MAX_WATCHERS];
04196 watchers[0] = in;
04197 start = NULL;
04198
04199 for (retry = 0; retry < 2; retry++) {
04200 numlines = 0;
04201 for (o = outgoing; o; o = o->q_next) {
04202 if (o->stillgoing) {
04203 stillgoing = 1;
04204 if (o->chan) {
04205 if (pos < AST_MAX_WATCHERS) {
04206 watchers[pos++] = o->chan;
04207 }
04208 if (!start) {
04209 start = o;
04210 } else {
04211 prev->call_next = o;
04212 }
04213 prev = o;
04214 }
04215 }
04216 numlines++;
04217 }
04218 if (pos > 1 || !stillgoing ||
04219 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) ) {
04220 break;
04221 }
04222
04223
04224 ring_one(qe, outgoing, &numbusies);
04225
04226 }
04227 if (pos == 1 ) {
04228 if (numlines == (numbusies + numnochan)) {
04229 ast_debug(1, "Everyone is busy at this time\n");
04230 } else {
04231 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
04232 }
04233 *to = 0;
04234 return NULL;
04235 }
04236
04237
04238 winner = ast_waitfor_n(watchers, pos, to);
04239
04240
04241 for (o = start; o; o = o->call_next) {
04242
04243
04244
04245 char ochan_name[AST_CHANNEL_NAME];
04246
04247 if (o->chan) {
04248 ast_channel_lock(o->chan);
04249 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
04250 ast_channel_unlock(o->chan);
04251 }
04252 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
04253 if (!peer) {
04254 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
04255 if (!o->block_connected_update) {
04256 if (o->pending_connected_update) {
04257 if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
04258 ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
04259 ast_channel_update_connected_line(in, &o->connected, NULL);
04260 }
04261 } else if (!o->dial_callerid_absent) {
04262 ast_channel_lock(o->chan);
04263 ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(o->chan));
04264 ast_channel_unlock(o->chan);
04265 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
04266 if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
04267 ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
04268 ast_channel_update_connected_line(in, &connected_caller, NULL);
04269 }
04270 ast_party_connected_line_free(&connected_caller);
04271 }
04272 }
04273 if (o->aoc_s_rate_list) {
04274 size_t encoded_size;
04275 struct ast_aoc_encoded *encoded;
04276 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
04277 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
04278 ast_aoc_destroy_encoded(encoded);
04279 }
04280 }
04281 peer = o;
04282 }
04283 } else if (o->chan && (o->chan == winner)) {
04284
04285 ast_copy_string(on, o->member->interface, sizeof(on));
04286 ast_copy_string(membername, o->member->membername, sizeof(membername));
04287
04288
04289 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
04290 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
04291 numnochan++;
04292 do_hang(o);
04293 winner = NULL;
04294 continue;
04295 } else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) {
04296 struct ast_channel *original = o->chan;
04297 char tmpchan[256];
04298 char *stuff;
04299 char *tech;
04300
04301 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
04302 if ((stuff = strchr(tmpchan, '/'))) {
04303 *stuff++ = '\0';
04304 tech = tmpchan;
04305 } else {
04306 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), ast_channel_context(o->chan));
04307 stuff = tmpchan;
04308 tech = "Local";
04309 }
04310 if (!strcasecmp(tech, "Local")) {
04311
04312
04313
04314
04315
04316 o->block_connected_update = 0;
04317 }
04318
04319 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, ast_channel_call_forward(o->chan), NULL);
04320
04321 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
04322
04323 o->chan = ast_request(tech, ast_channel_nativeformats(in), in, stuff, &status);
04324 if (!o->chan) {
04325 ast_log(LOG_NOTICE,
04326 "Forwarding failed to create channel to dial '%s/%s'\n",
04327 tech, stuff);
04328 o->stillgoing = 0;
04329 numnochan++;
04330 } else {
04331 ast_channel_lock_both(o->chan, original);
04332 ast_party_redirecting_copy(ast_channel_redirecting(o->chan),
04333 ast_channel_redirecting(original));
04334 ast_channel_unlock(o->chan);
04335 ast_channel_unlock(original);
04336
04337 ast_channel_lock_both(o->chan, in);
04338 ast_channel_inherit_variables(in, o->chan);
04339 ast_channel_datastore_inherit(in, o->chan);
04340
04341 if (o->pending_connected_update) {
04342
04343
04344
04345
04346
04347
04348 o->pending_connected_update = 0;
04349 ast_party_connected_line_copy(&o->connected, ast_channel_connected(in));
04350 }
04351
04352 ast_channel_accountcode_set(o->chan, ast_channel_accountcode(in));
04353
04354 if (!ast_channel_redirecting(o->chan)->from.number.valid
04355 || ast_strlen_zero(ast_channel_redirecting(o->chan)->from.number.str)) {
04356
04357
04358
04359
04360 ast_party_number_free(&ast_channel_redirecting(o->chan)->from.number);
04361 ast_party_number_init(&ast_channel_redirecting(o->chan)->from.number);
04362 ast_channel_redirecting(o->chan)->from.number.valid = 1;
04363 ast_channel_redirecting(o->chan)->from.number.str =
04364 ast_strdup(S_OR(ast_channel_macroexten(in), ast_channel_exten(in)));
04365 }
04366
04367 ast_channel_dialed(o->chan)->transit_network_select = ast_channel_dialed(in)->transit_network_select;
04368
04369 o->dial_callerid_absent = !ast_channel_caller(o->chan)->id.number.valid
04370 || ast_strlen_zero(ast_channel_caller(o->chan)->id.number.str);
04371 ast_connected_line_copy_from_caller(ast_channel_connected(o->chan),
04372 ast_channel_caller(in));
04373
04374 ast_channel_unlock(in);
04375 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL
04376 && !o->block_connected_update) {
04377 struct ast_party_redirecting redirecting;
04378
04379
04380
04381
04382
04383
04384
04385
04386
04387
04388
04389 ast_party_redirecting_init(&redirecting);
04390 ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(o->chan));
04391 ast_channel_unlock(o->chan);
04392 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0) &&
04393 ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
04394 ast_channel_update_redirecting(in, &redirecting, NULL);
04395 }
04396 ast_party_redirecting_free(&redirecting);
04397 } else {
04398 ast_channel_unlock(o->chan);
04399 }
04400
04401 if (ast_call(o->chan, stuff, 0)) {
04402 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
04403 tech, stuff);
04404 do_hang(o);
04405 numnochan++;
04406 }
04407 }
04408
04409 ast_hangup(winner);
04410 continue;
04411 }
04412 f = ast_read(winner);
04413 if (f) {
04414 if (f->frametype == AST_FRAME_CONTROL) {
04415 switch (f->subclass.integer) {
04416 case AST_CONTROL_ANSWER:
04417
04418 if (!peer) {
04419 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
04420 if (!o->block_connected_update) {
04421 if (o->pending_connected_update) {
04422 if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
04423 ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
04424 ast_channel_update_connected_line(in, &o->connected, NULL);
04425 }
04426 } else if (!o->dial_callerid_absent) {
04427 ast_channel_lock(o->chan);
04428 ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(o->chan));
04429 ast_channel_unlock(o->chan);
04430 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
04431 if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
04432 ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
04433 ast_channel_update_connected_line(in, &connected_caller, NULL);
04434 }
04435 ast_party_connected_line_free(&connected_caller);
04436 }
04437 }
04438 if (o->aoc_s_rate_list) {
04439 size_t encoded_size;
04440 struct ast_aoc_encoded *encoded;
04441 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
04442 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
04443 ast_aoc_destroy_encoded(encoded);
04444 }
04445 }
04446 peer = o;
04447 }
04448 break;
04449 case AST_CONTROL_BUSY:
04450 ast_verb(3, "%s is busy\n", ochan_name);
04451 if (ast_channel_cdr(in)) {
04452 ast_cdr_busy(ast_channel_cdr(in));
04453 }
04454 do_hang(o);
04455 endtime = (long) time(NULL);
04456 endtime -= starttime;
04457 rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy);
04458 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
04459 if (qe->parent->timeoutrestart) {
04460 start_time_tv = ast_tvnow();
04461 }
04462
04463 if (ast_remaining_ms(start_time_tv, orig) > 500) {
04464 ring_one(qe, outgoing, &numbusies);
04465 starttime = (long) time(NULL);
04466 }
04467 }
04468 numbusies++;
04469 break;
04470 case AST_CONTROL_CONGESTION:
04471 ast_verb(3, "%s is circuit-busy\n", ochan_name);
04472 if (ast_channel_cdr(in)) {
04473 ast_cdr_busy(ast_channel_cdr(in));
04474 }
04475 endtime = (long) time(NULL);
04476 endtime -= starttime;
04477 rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail);
04478 do_hang(o);
04479 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
04480 if (qe->parent->timeoutrestart) {
04481 start_time_tv = ast_tvnow();
04482 }
04483 if (ast_remaining_ms(start_time_tv, orig) > 500) {
04484 ring_one(qe, outgoing, &numbusies);
04485 starttime = (long) time(NULL);
04486 }
04487 }
04488 numbusies++;
04489 break;
04490 case AST_CONTROL_RINGING:
04491 ast_verb(3, "%s is ringing\n", ochan_name);
04492
04493
04494 if (qe->ring_when_ringing) {
04495 ast_moh_stop(qe->chan);
04496 ast_indicate(qe->chan, AST_CONTROL_RINGING);
04497 }
04498 break;
04499 case AST_CONTROL_OFFHOOK:
04500
04501 break;
04502 case AST_CONTROL_CONNECTED_LINE:
04503 if (o->block_connected_update) {
04504 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
04505 break;
04506 }
04507 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
04508 struct ast_party_connected_line connected;
04509
04510 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
04511 ast_party_connected_line_set_init(&connected, &o->connected);
04512 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
04513 ast_party_connected_line_set(&o->connected, &connected, NULL);
04514 ast_party_connected_line_free(&connected);
04515 o->pending_connected_update = 1;
04516 break;
04517 }
04518
04519
04520
04521
04522
04523 o->dial_callerid_absent = 1;
04524
04525 if (ast_channel_connected_line_sub(o->chan, in, f, 1) &&
04526 ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
04527 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
04528 }
04529 break;
04530 case AST_CONTROL_AOC:
04531 {
04532 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
04533 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
04534 ast_aoc_destroy_decoded(o->aoc_s_rate_list);
04535 o->aoc_s_rate_list = decoded;
04536 } else {
04537 ast_aoc_destroy_decoded(decoded);
04538 }
04539 }
04540 break;
04541 case AST_CONTROL_REDIRECTING:
04542 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
04543
04544
04545
04546
04547 break;
04548 }
04549 if (o->block_connected_update) {
04550 ast_verb(3, "Redirecting update to %s prevented\n",
04551 inchan_name);
04552 break;
04553 }
04554 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
04555 ochan_name, inchan_name);
04556 if (ast_channel_redirecting_sub(o->chan, in, f, 1) &&
04557 ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
04558 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
04559 }
04560 break;
04561 case AST_CONTROL_PVT_CAUSE_CODE:
04562 ast_indicate_data(in, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen);
04563 break;
04564 default:
04565 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
04566 break;
04567 }
04568 }
04569 ast_frfree(f);
04570 } else {
04571 endtime = (long) time(NULL) - starttime;
04572 rna(endtime * 1000, qe, on, membername, 1);
04573 do_hang(o);
04574 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
04575 if (qe->parent->timeoutrestart) {
04576 start_time_tv = ast_tvnow();
04577 }
04578 if (ast_remaining_ms(start_time_tv, orig) > 500) {
04579 ring_one(qe, outgoing, &numbusies);
04580 starttime = (long) time(NULL);
04581 }
04582 }
04583 }
04584 }
04585 }
04586
04587
04588 if (winner == in) {
04589 f = ast_read(in);
04590 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
04591
04592 *to = -1;
04593 if (f) {
04594 if (f->data.uint32) {
04595 ast_channel_hangupcause_set(in, f->data.uint32);
04596 }
04597 ast_frfree(f);
04598 }
04599 return NULL;
04600 }
04601
04602 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
04603 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
04604 *to = 0;
04605 ast_frfree(f);
04606 return NULL;
04607 }
04608 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
04609 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
04610 *to = 0;
04611 *digit = f->subclass.integer;
04612 ast_frfree(f);
04613 return NULL;
04614 }
04615
04616
04617 for (o = start; o; o = o->call_next) {
04618 if (!o->stillgoing || !o->chan) {
04619
04620 continue;
04621 }
04622 switch (f->frametype) {
04623 case AST_FRAME_CONTROL:
04624 switch (f->subclass.integer) {
04625 case AST_CONTROL_CONNECTED_LINE:
04626 if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
04627 ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
04628 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
04629 }
04630 break;
04631 case AST_CONTROL_REDIRECTING:
04632 if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
04633 ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
04634 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
04635 }
04636 break;
04637 default:
04638
04639 goto skip_frame;
04640 }
04641 break;
04642 default:
04643
04644 goto skip_frame;
04645 }
04646 }
04647 skip_frame:;
04648
04649 ast_frfree(f);
04650 }
04651 }
04652
04653
04654 if (qe->parent->announcefrequency && qe->parent->announce_to_first_user) {
04655 say_position(qe, ringing);
04656 }
04657
04658
04659 if (qe->parent->periodicannouncefrequency && qe->parent->announce_to_first_user) {
04660 say_periodic_announcement(qe, ringing);
04661 }
04662
04663 if (!*to) {
04664 for (o = start; o; o = o->call_next) {
04665 rna(orig, qe, o->interface, o->member->membername, 1);
04666 }
04667 }
04668
04669 #ifdef HAVE_EPOLL
04670 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
04671 if (epollo->chan) {
04672 ast_poll_channel_del(in, epollo->chan);
04673 }
04674 }
04675 #endif
04676
04677 return peer;
04678 }
04679
04680
04681
04682
04683
04684
04685
04686
04687
04688
04689
04690
04691 static int is_our_turn(struct queue_ent *qe)
04692 {
04693 struct queue_ent *ch;
04694 int res;
04695 int avl;
04696 int idx = 0;
04697
04698 ao2_lock(qe->parent);
04699
04700 avl = num_available_members(qe->parent);
04701
04702 ch = qe->parent->head;
04703
04704 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
04705
04706 while ((idx < avl) && (ch) && (ch != qe)) {
04707 if (!ch->pending) {
04708 idx++;
04709 }
04710 ch = ch->next;
04711 }
04712
04713 ao2_unlock(qe->parent);
04714
04715
04716
04717
04718 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
04719 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
04720 res = 1;
04721 } else {
04722 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
04723 res = 0;
04724 }
04725
04726 return res;
04727 }
04728
04729
04730
04731
04732
04733
04734
04735 static void update_qe_rule(struct queue_ent *qe)
04736 {
04737 int max_penalty = INT_MAX;
04738
04739 if (qe->max_penalty != INT_MAX) {
04740 char max_penalty_str[20];
04741
04742 if (qe->pr->max_relative) {
04743 max_penalty = qe->max_penalty + qe->pr->max_value;
04744 } else {
04745 max_penalty = qe->pr->max_value;
04746 }
04747
04748
04749 if (max_penalty < 0) {
04750 max_penalty = 0;
04751 }
04752
04753 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
04754 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
04755 qe->max_penalty = max_penalty;
04756 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
04757 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
04758 }
04759
04760 if (qe->min_penalty != INT_MAX) {
04761 char min_penalty_str[20];
04762 int min_penalty;
04763
04764 if (qe->pr->min_relative) {
04765 min_penalty = qe->min_penalty + qe->pr->min_value;
04766 } else {
04767 min_penalty = qe->pr->min_value;
04768 }
04769
04770
04771 if (min_penalty < 0) {
04772 min_penalty = 0;
04773 }
04774
04775 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
04776 min_penalty = max_penalty;
04777 }
04778
04779 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
04780 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
04781 qe->min_penalty = min_penalty;
04782 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
04783 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
04784 }
04785
04786 qe->pr = AST_LIST_NEXT(qe->pr, list);
04787 }
04788
04789
04790
04791
04792
04793
04794
04795
04796
04797
04798
04799 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
04800 {
04801 int res = 0;
04802
04803
04804 for (;;) {
04805
04806 if (is_our_turn(qe)) {
04807 break;
04808 }
04809
04810
04811 if (qe->expire && (time(NULL) >= qe->expire)) {
04812 *reason = QUEUE_TIMEOUT;
04813 break;
04814 }
04815
04816 if (qe->parent->leavewhenempty) {
04817 int status = 0;
04818
04819 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) {
04820 *reason = QUEUE_LEAVEEMPTY;
04821 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
04822 leave_queue(qe);
04823 break;
04824 }
04825 }
04826
04827
04828 if (qe->parent->announcefrequency &&
04829 (res = say_position(qe,ringing))) {
04830 break;
04831 }
04832
04833
04834 if (qe->expire && (time(NULL) >= qe->expire)) {
04835 *reason = QUEUE_TIMEOUT;
04836 break;
04837 }
04838
04839
04840 if (qe->parent->periodicannouncefrequency &&
04841 (res = say_periodic_announcement(qe,ringing)))
04842 break;
04843
04844
04845 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
04846 update_qe_rule(qe);
04847 }
04848
04849
04850 if (qe->expire && (time(NULL) >= qe->expire)) {
04851 *reason = QUEUE_TIMEOUT;
04852 break;
04853 }
04854
04855
04856 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
04857 if (res > 0 && !valid_exit(qe, res)) {
04858 res = 0;
04859 } else {
04860 break;
04861 }
04862 }
04863
04864
04865 if (qe->expire && (time(NULL) >= qe->expire)) {
04866 *reason = QUEUE_TIMEOUT;
04867 break;
04868 }
04869 }
04870
04871 return res;
04872 }
04873
04874
04875
04876
04877
04878 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
04879 {
04880 int oldtalktime;
04881
04882 struct member *mem;
04883 struct call_queue *qtmp;
04884 struct ao2_iterator queue_iter;
04885
04886 if (shared_lastcall) {
04887 queue_iter = ao2_iterator_init(queues, 0);
04888 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
04889 ao2_lock(qtmp);
04890 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
04891 time(&mem->lastcall);
04892 mem->calls++;
04893 mem->lastqueue = q;
04894 ao2_ref(mem, -1);
04895 }
04896 ao2_unlock(qtmp);
04897 queue_t_unref(qtmp, "Done with iterator");
04898 }
04899 ao2_iterator_destroy(&queue_iter);
04900 } else {
04901 ao2_lock(q);
04902 time(&member->lastcall);
04903 member->calls++;
04904 member->lastqueue = q;
04905 ao2_unlock(q);
04906 }
04907 ao2_lock(q);
04908 q->callscompleted++;
04909 if (callcompletedinsl) {
04910 q->callscompletedinsl++;
04911 }
04912
04913 oldtalktime = q->talktime;
04914 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
04915 ao2_unlock(q);
04916 return 0;
04917 }
04918
04919
04920
04921
04922
04923
04924
04925
04926
04927 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
04928 {
04929
04930 int membercount = ao2_container_count(q->members);
04931 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
04932
04933 if (usepenalty) {
04934 if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) ||
04935 (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) {
04936 return -1;
04937 }
04938 } else {
04939 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
04940 membercount, q->penaltymemberslimit);
04941 }
04942
04943 switch (q->strategy) {
04944 case QUEUE_STRATEGY_RINGALL:
04945
04946 tmp->metric = mem->penalty * 1000000 * usepenalty;
04947 break;
04948 case QUEUE_STRATEGY_LINEAR:
04949 if (pos < qe->linpos) {
04950 tmp->metric = 1000 + pos;
04951 } else {
04952 if (pos > qe->linpos) {
04953
04954 qe->linwrapped = 1;
04955 }
04956 tmp->metric = pos;
04957 }
04958 tmp->metric += mem->penalty * 1000000 * usepenalty;
04959 break;
04960 case QUEUE_STRATEGY_RRORDERED:
04961 case QUEUE_STRATEGY_RRMEMORY:
04962 pos = mem->queuepos;
04963 if (pos < q->rrpos) {
04964 tmp->metric = 1000 + pos;
04965 } else {
04966 if (pos > q->rrpos) {
04967
04968 q->wrapped = 1;
04969 }
04970 tmp->metric = pos;
04971 }
04972 tmp->metric += mem->penalty * 1000000 * usepenalty;
04973 break;
04974 case QUEUE_STRATEGY_RANDOM:
04975 tmp->metric = ast_random() % 1000;
04976 tmp->metric += mem->penalty * 1000000 * usepenalty;
04977 break;
04978 case QUEUE_STRATEGY_WRANDOM:
04979 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
04980 break;
04981 case QUEUE_STRATEGY_FEWESTCALLS:
04982 tmp->metric = mem->calls;
04983 tmp->metric += mem->penalty * 1000000 * usepenalty;
04984 break;
04985 case QUEUE_STRATEGY_LEASTRECENT:
04986 if (!mem->lastcall) {
04987 tmp->metric = 0;
04988 } else {
04989 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
04990 }
04991 tmp->metric += mem->penalty * 1000000 * usepenalty;
04992 break;
04993 default:
04994 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
04995 break;
04996 }
04997 return 0;
04998 }
04999
05000 enum agent_complete_reason {
05001 CALLER,
05002 AGENT,
05003 TRANSFER
05004 };
05005
05006
05007 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
05008 const struct ast_channel *peer, const struct member *member, time_t callstart,
05009 char *vars, size_t vars_len, enum agent_complete_reason rsn)
05010 {
05011 const char *reason = NULL;
05012
05013 if (!qe->parent->eventwhencalled) {
05014 return;
05015 }
05016
05017 switch (rsn) {
05018 case CALLER:
05019 reason = "caller";
05020 break;
05021 case AGENT:
05022 reason = "agent";
05023 break;
05024 case TRANSFER:
05025 reason = "transfer";
05026 break;
05027 }
05028
05029
05030
05031
05032
05033
05034
05035
05036
05037
05038
05039
05040
05041
05042
05043
05044
05045
05046
05047
05048
05049
05050
05051
05052
05053
05054
05055 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
05056 "Queue: %s\r\n"
05057 "Uniqueid: %s\r\n"
05058 "Channel: %s\r\n"
05059 "Member: %s\r\n"
05060 "MemberName: %s\r\n"
05061 "HoldTime: %ld\r\n"
05062 "TalkTime: %ld\r\n"
05063 "Reason: %s\r\n"
05064 "%s",
05065 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
05066 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
05067 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
05068 }
05069
05070 struct queue_transfer_ds {
05071 struct queue_ent *qe;
05072 struct member *member;
05073 time_t starttime;
05074 int callcompletedinsl;
05075 };
05076
05077 static void queue_transfer_destroy(void *data)
05078 {
05079 struct queue_transfer_ds *qtds = data;
05080 ast_free(qtds);
05081 }
05082
05083
05084
05085 static const struct ast_datastore_info queue_transfer_info = {
05086 .type = "queue_transfer",
05087 .chan_fixup = queue_transfer_fixup,
05088 .destroy = queue_transfer_destroy,
05089 };
05090
05091
05092
05093
05094
05095
05096
05097
05098
05099
05100 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
05101 {
05102 struct queue_transfer_ds *qtds = data;
05103 struct queue_ent *qe = qtds->qe;
05104 struct member *member = qtds->member;
05105 time_t callstart = qtds->starttime;
05106 int callcompletedinsl = qtds->callcompletedinsl;
05107 struct ast_datastore *datastore;
05108
05109 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
05110 ast_channel_exten(new_chan), ast_channel_context(new_chan), (long) (callstart - qe->start),
05111 (long) (time(NULL) - callstart), qe->opos);
05112
05113 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
05114
05115
05116 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
05117 ast_channel_datastore_remove(old_chan, datastore);
05118 } else {
05119 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
05120 }
05121 }
05122
05123
05124
05125
05126
05127
05128
05129
05130
05131 static int attended_transfer_occurred(struct ast_channel *chan)
05132 {
05133 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
05134 }
05135
05136
05137
05138 static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
05139 {
05140 struct ast_datastore *ds;
05141 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
05142
05143 if (!qtds) {
05144 ast_log(LOG_WARNING, "Memory allocation error!\n");
05145 return NULL;
05146 }
05147
05148 ast_channel_lock(qe->chan);
05149 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
05150 ast_channel_unlock(qe->chan);
05151 ast_free(qtds);
05152 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
05153 return NULL;
05154 }
05155
05156 qtds->qe = qe;
05157
05158 qtds->member = member;
05159 qtds->starttime = starttime;
05160 qtds->callcompletedinsl = callcompletedinsl;
05161 ds->data = qtds;
05162 ast_channel_datastore_add(qe->chan, ds);
05163 ast_channel_unlock(qe->chan);
05164 return ds;
05165 }
05166
05167 struct queue_end_bridge {
05168 struct call_queue *q;
05169 struct ast_channel *chan;
05170 };
05171
05172 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
05173 {
05174 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
05175 ao2_ref(qeb, +1);
05176 qeb->chan = originator;
05177 }
05178
05179 static void end_bridge_callback(void *data)
05180 {
05181 struct queue_end_bridge *qeb = data;
05182 struct call_queue *q = qeb->q;
05183 struct ast_channel *chan = qeb->chan;
05184
05185 if (ao2_ref(qeb, -1) == 1) {
05186 set_queue_variables(q, chan);
05187
05188 queue_t_unref(q, "Expire bridge_config reference");
05189 }
05190 }
05191
05192
05193
05194
05195
05196
05197
05198
05199
05200
05201
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218
05219
05220
05221
05222 static int try_calling(struct queue_ent *qe, const struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
05223 {
05224 struct member *cur;
05225 struct callattempt *outgoing = NULL;
05226 int to, orig;
05227 char oldexten[AST_MAX_EXTENSION]="";
05228 char oldcontext[AST_MAX_CONTEXT]="";
05229 char queuename[256]="";
05230 char interfacevar[256]="";
05231 struct ast_channel *peer;
05232 struct ast_channel *which;
05233 struct callattempt *lpeer;
05234 struct member *member;
05235 struct ast_app *application;
05236 int res = 0, bridge = 0;
05237 int numbusies = 0;
05238 int x=0;
05239 char *announce = NULL;
05240 char digit = 0;
05241 time_t callstart;
05242 time_t now = time(NULL);
05243 struct ast_bridge_config bridge_config;
05244 char nondataquality = 1;
05245 char *agiexec = NULL;
05246 char *macroexec = NULL;
05247 char *gosubexec = NULL;
05248 const char *monitorfilename;
05249 const char *monitor_exec;
05250 const char *monitor_options;
05251 char tmpid[256], tmpid2[256];
05252 char meid[1024], meid2[1024];
05253 char mixmonargs[1512];
05254 struct ast_app *mixmonapp = NULL;
05255 char *p;
05256 char vars[2048];
05257 int forwardsallowed = 1;
05258 int block_connected_line = 0;
05259 int callcompletedinsl;
05260 struct ao2_iterator memi;
05261 struct ast_datastore *datastore, *transfer_ds;
05262 struct queue_end_bridge *queue_end_bridge = NULL;
05263
05264 ast_channel_lock(qe->chan);
05265 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
05266 ast_channel_unlock(qe->chan);
05267
05268 memset(&bridge_config, 0, sizeof(bridge_config));
05269 tmpid[0] = 0;
05270 meid[0] = 0;
05271 time(&now);
05272
05273
05274
05275
05276
05277 if (qe->expire && now >= qe->expire) {
05278 res = 0;
05279 goto out;
05280 }
05281
05282 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
05283 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
05284 }
05285 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
05286 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
05287 }
05288 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
05289 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
05290 }
05291 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
05292 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
05293 }
05294 if (ast_test_flag(&opts, OPT_GO_ON)) {
05295 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
05296 }
05297 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
05298 nondataquality = 0;
05299 }
05300 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
05301 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
05302 }
05303 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
05304 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
05305 }
05306 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
05307 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
05308 }
05309 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
05310 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
05311 }
05312 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
05313 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR
05314 || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
05315 (*tries)++;
05316 } else {
05317 *tries = ao2_container_count(qe->parent->members);
05318 }
05319 *noption = 1;
05320 }
05321 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
05322 forwardsallowed = 0;
05323 }
05324 if (ast_test_flag(&opts, OPT_IGNORE_CONNECTEDLINE)) {
05325 block_connected_line = 1;
05326 }
05327 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMIXMON)) {
05328 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
05329 }
05330 if (ast_test_flag(&opts, OPT_CALLER_AUTOMIXMON)) {
05331 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
05332 }
05333 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
05334 qe->cancel_answered_elsewhere = 1;
05335 }
05336
05337
05338
05339
05340 if (ast_channel_hangupcause(qe->chan) == AST_CAUSE_ANSWERED_ELSEWHERE) {
05341 qe->cancel_answered_elsewhere = 1;
05342 }
05343
05344 ao2_lock(qe->parent);
05345 ast_debug(1, "%s is trying to call a queue member.\n",
05346 ast_channel_name(qe->chan));
05347 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
05348 if (!ast_strlen_zero(qe->announce)) {
05349 announce = qe->announce;
05350 }
05351 if (!ast_strlen_zero(announceoverride)) {
05352 announce = announceoverride;
05353 }
05354
05355 memi = ao2_iterator_init(qe->parent->members, 0);
05356 while ((cur = ao2_iterator_next(&memi))) {
05357 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
05358 struct ast_dialed_interface *di;
05359 AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
05360 if (!tmp) {
05361 ao2_ref(cur, -1);
05362 ao2_iterator_destroy(&memi);
05363 ao2_unlock(qe->parent);
05364 goto out;
05365 }
05366 if (!datastore) {
05367 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
05368 callattempt_free(tmp);
05369 ao2_ref(cur, -1);
05370 ao2_iterator_destroy(&memi);
05371 ao2_unlock(qe->parent);
05372 goto out;
05373 }
05374 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
05375 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
05376 callattempt_free(tmp);
05377 ao2_ref(cur, -1);
05378 ao2_iterator_destroy(&memi);
05379 ao2_unlock(qe->parent);
05380 goto out;
05381 }
05382 datastore->data = dialed_interfaces;
05383 AST_LIST_HEAD_INIT(dialed_interfaces);
05384
05385 ast_channel_lock(qe->chan);
05386 ast_channel_datastore_add(qe->chan, datastore);
05387 ast_channel_unlock(qe->chan);
05388 } else
05389 dialed_interfaces = datastore->data;
05390
05391 AST_LIST_LOCK(dialed_interfaces);
05392 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
05393 if (!strcasecmp(cur->interface, di->interface)) {
05394 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n",
05395 di->interface);
05396 break;
05397 }
05398 }
05399 AST_LIST_UNLOCK(dialed_interfaces);
05400
05401 if (di) {
05402 callattempt_free(tmp);
05403 ao2_ref(cur, -1);
05404 continue;
05405 }
05406
05407
05408
05409
05410
05411 if (strncasecmp(cur->interface, "Local/", 6)) {
05412 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
05413 callattempt_free(tmp);
05414 ao2_ref(cur, -1);
05415 ao2_iterator_destroy(&memi);
05416 ao2_unlock(qe->parent);
05417 goto out;
05418 }
05419 strcpy(di->interface, cur->interface);
05420
05421 AST_LIST_LOCK(dialed_interfaces);
05422 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
05423 AST_LIST_UNLOCK(dialed_interfaces);
05424 }
05425
05426
05427
05428
05429
05430
05431
05432 ast_channel_lock(qe->chan);
05433 ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(qe->chan));
05434 ast_channel_unlock(qe->chan);
05435
05436 tmp->block_connected_update = block_connected_line;
05437 tmp->stillgoing = 1;
05438 tmp->member = cur;
05439 tmp->lastcall = cur->lastcall;
05440 tmp->lastqueue = cur->lastqueue;
05441 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
05442
05443
05444 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
05445
05446
05447
05448 tmp->q_next = outgoing;
05449 outgoing = tmp;
05450
05451 if (outgoing->chan && (ast_channel_state(outgoing->chan) == AST_STATE_UP))
05452 break;
05453 } else {
05454 callattempt_free(tmp);
05455 }
05456 }
05457 ao2_iterator_destroy(&memi);
05458
05459 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
05460
05461 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
05462 to = (qe->expire - now) * 1000;
05463 } else {
05464 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
05465 }
05466 } else {
05467
05468 if (qe->expire && qe->expire<=now) {
05469 to = 0;
05470 } else if (qe->parent->timeout) {
05471 to = qe->parent->timeout * 1000;
05472 } else {
05473 to = -1;
05474 }
05475 }
05476 orig = to;
05477 ++qe->pending;
05478 ao2_unlock(qe->parent);
05479 ring_one(qe, outgoing, &numbusies);
05480 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
05481 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
05482 forwardsallowed, ringing);
05483
05484
05485
05486
05487
05488
05489 ast_channel_lock(qe->chan);
05490 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
05491 ast_datastore_free(datastore);
05492 }
05493 ast_channel_unlock(qe->chan);
05494 ao2_lock(qe->parent);
05495 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
05496 store_next_rr(qe, outgoing);
05497
05498 }
05499 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
05500 store_next_lin(qe, outgoing);
05501 }
05502 ao2_unlock(qe->parent);
05503 peer = lpeer ? lpeer->chan : NULL;
05504 if (!peer) {
05505 qe->pending = 0;
05506 if (to) {
05507
05508 res = -1;
05509 } else {
05510
05511 res = digit;
05512 }
05513 if (res == -1) {
05514 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
05515 }
05516 if (ast_cdr_isset_unanswered()) {
05517
05518
05519 struct callattempt *o;
05520 for (o = outgoing; o; o = o->q_next) {
05521 if (!o->chan) {
05522 continue;
05523 }
05524 if (strcmp(ast_channel_cdr(o->chan)->dstchannel, ast_channel_cdr(qe->chan)->dstchannel) == 0) {
05525 ast_set_flag(ast_channel_cdr(o->chan), AST_CDR_FLAG_POST_DISABLED);
05526 break;
05527 }
05528 }
05529 }
05530 } else {
05531
05532 char *caller_context;
05533 char *caller_extension;
05534 int caller_priority;
05535
05536
05537
05538
05539 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
05540 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
05541 }
05542 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
05543 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
05544 }
05545
05546 time(&now);
05547 recalc_holdtime(qe, (now - qe->start));
05548 ao2_lock(qe->parent);
05549 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
05550 ao2_unlock(qe->parent);
05551 member = lpeer->member;
05552
05553 ao2_ref(member, 1);
05554 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
05555 outgoing = NULL;
05556 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
05557 int res2;
05558
05559 res2 = ast_autoservice_start(qe->chan);
05560 if (!res2) {
05561 if (qe->parent->memberdelay) {
05562 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
05563 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
05564 }
05565 if (!res2 && announce) {
05566 if (play_file(peer, announce) < 0) {
05567 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, ast_channel_name(peer));
05568 }
05569 }
05570 if (!res2 && qe->parent->reportholdtime) {
05571 if (!play_file(peer, qe->parent->sound_reporthold)) {
05572 int holdtime, holdtimesecs;
05573
05574 time(&now);
05575 holdtime = abs((now - qe->start) / 60);
05576 holdtimesecs = abs((now - qe->start) % 60);
05577 if (holdtime > 0) {
05578 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
05579 if (play_file(peer, qe->parent->sound_minutes) < 0) {
05580 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
05581 }
05582 }
05583 if (holdtimesecs > 1) {
05584 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
05585 if (play_file(peer, qe->parent->sound_seconds) < 0) {
05586 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
05587 }
05588 }
05589 }
05590 }
05591 ast_autoservice_stop(qe->chan);
05592 }
05593 if (ast_check_hangup(peer)) {
05594
05595 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
05596 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
05597 if (qe->parent->eventwhencalled)
05598
05599
05600
05601
05602
05603
05604
05605
05606
05607
05608
05609
05610
05611
05612
05613 manager_event(EVENT_FLAG_AGENT, "AgentDump",
05614 "Queue: %s\r\n"
05615 "Uniqueid: %s\r\n"
05616 "Channel: %s\r\n"
05617 "Member: %s\r\n"
05618 "MemberName: %s\r\n"
05619 "%s",
05620 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
05621 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
05622 ast_autoservice_chan_hangup_peer(qe->chan, peer);
05623 ao2_ref(member, -1);
05624 goto out;
05625 } else if (ast_check_hangup(qe->chan)) {
05626
05627 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
05628 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
05629 record_abandoned(qe);
05630 ast_autoservice_chan_hangup_peer(qe->chan, peer);
05631 ao2_ref(member, -1);
05632 return -1;
05633 }
05634 }
05635
05636 if (ringing) {
05637 ast_indicate(qe->chan,-1);
05638 } else {
05639 ast_moh_stop(qe->chan);
05640 }
05641
05642 if (ast_channel_cdr(qe->chan)) {
05643 ast_cdr_setdestchan(ast_channel_cdr(qe->chan), ast_channel_name(peer));
05644 }
05645
05646 res = ast_channel_make_compatible(qe->chan, peer);
05647 if (res < 0) {
05648 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
05649 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
05650 record_abandoned(qe);
05651 ast_cdr_failed(ast_channel_cdr(qe->chan));
05652 ast_autoservice_chan_hangup_peer(qe->chan, peer);
05653 ao2_ref(member, -1);
05654 return -1;
05655 }
05656
05657
05658 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
05659 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
05660 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
05661 }
05662 }
05663
05664 ao2_lock(qe->parent);
05665
05666
05667 if (qe->parent->setinterfacevar) {
05668 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
05669 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
05670 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
05671 pbx_builtin_setvar_multiple(peer, interfacevar);
05672 }
05673
05674
05675
05676 if (qe->parent->setqueueentryvar) {
05677 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
05678 (long) time(NULL) - qe->start, qe->opos);
05679 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
05680 pbx_builtin_setvar_multiple(peer, interfacevar);
05681 }
05682
05683 ao2_unlock(qe->parent);
05684
05685
05686 set_queue_variables(qe->parent, qe->chan);
05687 set_queue_variables(qe->parent, peer);
05688
05689 ast_channel_lock(qe->chan);
05690
05691 caller_context = ast_strdupa(ast_channel_context(qe->chan));
05692 caller_extension = ast_strdupa(ast_channel_exten(qe->chan));
05693 caller_priority = ast_channel_priority(qe->chan);
05694 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
05695 monitorfilename = ast_strdupa(monitorfilename);
05696 }
05697 ast_channel_unlock(qe->chan);
05698
05699
05700 if (qe->parent->monfmt && *qe->parent->monfmt) {
05701 if (!qe->parent->montype) {
05702 const char *monexec;
05703 ast_debug(1, "Starting Monitor as requested.\n");
05704 ast_channel_lock(qe->chan);
05705 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
05706 which = qe->chan;
05707 monexec = monexec ? ast_strdupa(monexec) : NULL;
05708 } else {
05709 which = peer;
05710 }
05711 ast_channel_unlock(qe->chan);
05712 if (monitorfilename) {
05713 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
05714 } else if (ast_channel_cdr(qe->chan)) {
05715 ast_monitor_start(which, qe->parent->monfmt, ast_channel_cdr(qe->chan)->uniqueid, 1, X_REC_IN | X_REC_OUT);
05716 } else {
05717
05718 snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
05719 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
05720 }
05721 if (!ast_strlen_zero(monexec)) {
05722 ast_monitor_setjoinfiles(which, 1);
05723 }
05724 } else {
05725 mixmonapp = pbx_findapp("MixMonitor");
05726
05727 if (mixmonapp) {
05728 ast_debug(1, "Starting MixMonitor as requested.\n");
05729 if (!monitorfilename) {
05730 if (ast_channel_cdr(qe->chan)) {
05731 ast_copy_string(tmpid, ast_channel_cdr(qe->chan)->uniqueid, sizeof(tmpid));
05732 } else {
05733 snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
05734 }
05735 } else {
05736 const char *m = monitorfilename;
05737 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
05738 switch (*m) {
05739 case '^':
05740 if (*(m + 1) == '{')
05741 *p = '$';
05742 break;
05743 case ',':
05744 *p++ = '\\';
05745
05746 default:
05747 *p = *m;
05748 }
05749 if (*m == '\0')
05750 break;
05751 }
05752 if (p == tmpid2 + sizeof(tmpid2))
05753 tmpid2[sizeof(tmpid2) - 1] = '\0';
05754
05755 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
05756 }
05757
05758 ast_channel_lock(qe->chan);
05759 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
05760 monitor_exec = ast_strdupa(monitor_exec);
05761 }
05762 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
05763 monitor_options = ast_strdupa(monitor_options);
05764 } else {
05765 monitor_options = "";
05766 }
05767 ast_channel_unlock(qe->chan);
05768
05769 if (monitor_exec) {
05770 const char *m = monitor_exec;
05771 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
05772 switch (*m) {
05773 case '^':
05774 if (*(m + 1) == '{')
05775 *p = '$';
05776 break;
05777 case ',':
05778 *p++ = '\\';
05779
05780 default:
05781 *p = *m;
05782 }
05783 if (*m == '\0') {
05784 break;
05785 }
05786 }
05787 if (p == meid2 + sizeof(meid2)) {
05788 meid2[sizeof(meid2) - 1] = '\0';
05789 }
05790
05791 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
05792 }
05793
05794 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
05795
05796 if (!ast_strlen_zero(monitor_exec)) {
05797 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
05798 } else {
05799 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
05800 }
05801
05802 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
05803
05804 if (ast_channel_cdr(qe->chan)) {
05805 ast_set_flag(ast_channel_cdr(qe->chan), AST_CDR_FLAG_LOCKED);
05806 }
05807 pbx_exec(qe->chan, mixmonapp, mixmonargs);
05808 if (ast_channel_cdr(qe->chan)) {
05809 ast_clear_flag(ast_channel_cdr(qe->chan), AST_CDR_FLAG_LOCKED);
05810 }
05811 } else {
05812 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
05813 }
05814 }
05815 }
05816
05817 leave_queue(qe);
05818 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
05819 ast_debug(1, "app_queue: sendurl=%s.\n", url);
05820 ast_channel_sendurl(peer, url);
05821 }
05822
05823
05824
05825 if (!ast_strlen_zero(macro)) {
05826 macroexec = ast_strdupa(macro);
05827 } else {
05828 if (qe->parent->membermacro) {
05829 macroexec = ast_strdupa(qe->parent->membermacro);
05830 }
05831 }
05832
05833 if (!ast_strlen_zero(macroexec)) {
05834 ast_debug(1, "app_queue: macro=%s.\n", macroexec);
05835 ast_app_exec_macro(qe->chan, peer, macroexec);
05836 }
05837
05838
05839
05840 if (!ast_strlen_zero(gosub)) {
05841 gosubexec = ast_strdupa(gosub);
05842 } else {
05843 if (qe->parent->membergosub) {
05844 gosubexec = ast_strdupa(qe->parent->membergosub);
05845 }
05846 }
05847
05848 if (!ast_strlen_zero(gosubexec)) {
05849 char *gosub_args = NULL;
05850 char *gosub_argstart;
05851
05852 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
05853
05854 gosub_argstart = strchr(gosubexec, ',');
05855 if (gosub_argstart) {
05856 const char *what_is_s = "s";
05857 *gosub_argstart = 0;
05858 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
05859 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
05860 what_is_s = "~~s~~";
05861 }
05862 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
05863 gosub_args = NULL;
05864 }
05865 *gosub_argstart = ',';
05866 } else {
05867 const char *what_is_s = "s";
05868 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
05869 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
05870 what_is_s = "~~s~~";
05871 }
05872 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
05873 gosub_args = NULL;
05874 }
05875 }
05876 if (gosub_args) {
05877 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
05878 ast_free(gosub_args);
05879 } else {
05880 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
05881 }
05882 }
05883
05884 if (!ast_strlen_zero(agi)) {
05885 ast_debug(1, "app_queue: agi=%s.\n", agi);
05886 application = pbx_findapp("agi");
05887 if (application) {
05888 agiexec = ast_strdupa(agi);
05889 pbx_exec(qe->chan, application, agiexec);
05890 } else {
05891 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
05892 }
05893 }
05894 qe->handled++;
05895 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, ast_channel_uniqueid(peer),
05896 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
05897
05898 if (ast_channel_cdr(qe->chan)) {
05899 struct ast_cdr *cdr;
05900 struct ast_cdr *newcdr;
05901
05902
05903 cdr = ast_channel_cdr(qe->chan);
05904 while (cdr->next) {
05905 cdr = cdr->next;
05906 }
05907
05908
05909 if ((strcasecmp(cdr->uniqueid, ast_channel_uniqueid(qe->chan))) &&
05910 (strcasecmp(cdr->linkedid, ast_channel_uniqueid(qe->chan))) &&
05911 (newcdr = ast_cdr_dup(cdr))) {
05912 ast_channel_lock(qe->chan);
05913 ast_cdr_init(newcdr, qe->chan);
05914 ast_cdr_reset(newcdr, 0);
05915 cdr = ast_cdr_append(cdr, newcdr);
05916 cdr = cdr->next;
05917 ast_channel_unlock(qe->chan);
05918 }
05919
05920 if (update_cdr) {
05921 ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
05922 }
05923 }
05924
05925 if (qe->parent->eventwhencalled)
05926
05927
05928
05929
05930
05931
05932
05933
05934
05935
05936
05937
05938
05939
05940
05941
05942
05943
05944 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
05945 "Queue: %s\r\n"
05946 "Uniqueid: %s\r\n"
05947 "Channel: %s\r\n"
05948 "Member: %s\r\n"
05949 "MemberName: %s\r\n"
05950 "HoldTime: %ld\r\n"
05951 "BridgedChannel: %s\r\n"
05952 "RingTime: %ld\r\n"
05953 "%s",
05954 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
05955 (long) time(NULL) - qe->start, ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
05956 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
05957 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
05958 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
05959
05960 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
05961 queue_end_bridge->q = qe->parent;
05962 queue_end_bridge->chan = qe->chan;
05963 bridge_config.end_bridge_callback = end_bridge_callback;
05964 bridge_config.end_bridge_callback_data = queue_end_bridge;
05965 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
05966
05967
05968
05969
05970 queue_t_ref(qe->parent, "For bridge_config reference");
05971 }
05972
05973 time(&callstart);
05974 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
05975 bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
05976
05977
05978
05979
05980
05981 ast_channel_lock(qe->chan);
05982 if (!attended_transfer_occurred(qe->chan)) {
05983 struct ast_datastore *tds;
05984
05985
05986 if (!(ast_channel_softhangup_internal_flag(qe->chan) | ast_channel_softhangup_internal_flag(peer)) && (strcasecmp(oldcontext, ast_channel_context(qe->chan)) || strcasecmp(oldexten, ast_channel_exten(qe->chan)))) {
05987 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
05988 ast_channel_exten(qe->chan), ast_channel_context(qe->chan), (long) (callstart - qe->start),
05989 (long) (time(NULL) - callstart), qe->opos);
05990 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05991 } else if (ast_check_hangup(qe->chan) && !ast_check_hangup(peer)) {
05992 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETECALLER", "%ld|%ld|%d",
05993 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05994 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
05995 } else {
05996 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
05997 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05998 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
05999 }
06000 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
06001 ast_channel_datastore_remove(qe->chan, tds);
06002 }
06003 ast_channel_unlock(qe->chan);
06004 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
06005 } else {
06006 ast_channel_unlock(qe->chan);
06007
06008
06009 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
06010 }
06011
06012 if (transfer_ds) {
06013 ast_datastore_free(transfer_ds);
06014 }
06015
06016 if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
06017 int goto_res;
06018
06019 if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
06020 ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
06021 goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
06022 } else {
06023 goto_res = ast_goto_if_exists(peer, caller_context, caller_extension,
06024 caller_priority + 1);
06025 }
06026 if (goto_res || ast_pbx_start(peer)) {
06027 ast_autoservice_chan_hangup_peer(qe->chan, peer);
06028 }
06029 } else {
06030 ast_autoservice_chan_hangup_peer(qe->chan, peer);
06031 }
06032
06033 res = bridge ? bridge : 1;
06034 ao2_ref(member, -1);
06035 }
06036 out:
06037 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
06038
06039 return res;
06040 }
06041
06042 static int wait_a_bit(struct queue_ent *qe)
06043 {
06044
06045 int retrywait = qe->parent->retry * 1000;
06046
06047 int res = ast_waitfordigit(qe->chan, retrywait);
06048 if (res > 0 && !valid_exit(qe, res)) {
06049 res = 0;
06050 }
06051
06052 return res;
06053 }
06054
06055 static struct member *interface_exists(struct call_queue *q, const char *interface)
06056 {
06057 struct member *mem;
06058 struct ao2_iterator mem_iter;
06059
06060 if (!q) {
06061 return NULL;
06062 }
06063 mem_iter = ao2_iterator_init(q->members, 0);
06064 while ((mem = ao2_iterator_next(&mem_iter))) {
06065 if (!strcasecmp(interface, mem->interface)) {
06066 ao2_iterator_destroy(&mem_iter);
06067 return mem;
06068 }
06069 ao2_ref(mem, -1);
06070 }
06071 ao2_iterator_destroy(&mem_iter);
06072
06073 return NULL;
06074 }
06075
06076
06077
06078
06079
06080
06081 static void dump_queue_members(struct call_queue *pm_queue)
06082 {
06083 struct member *cur_member;
06084 struct ast_str *value;
06085 struct ao2_iterator mem_iter;
06086
06087 if (!pm_queue) {
06088 return;
06089 }
06090
06091
06092
06093 if (!(value = ast_str_create(4096))) {
06094 return;
06095 }
06096
06097 mem_iter = ao2_iterator_init(pm_queue->members, 0);
06098 while ((cur_member = ao2_iterator_next(&mem_iter))) {
06099 if (!cur_member->dynamic) {
06100 ao2_ref(cur_member, -1);
06101 continue;
06102 }
06103
06104 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s",
06105 ast_str_strlen(value) ? "|" : "",
06106 cur_member->interface,
06107 cur_member->penalty,
06108 cur_member->paused,
06109 cur_member->membername,
06110 cur_member->state_interface);
06111
06112 ao2_ref(cur_member, -1);
06113 }
06114 ao2_iterator_destroy(&mem_iter);
06115
06116 if (ast_str_strlen(value) && !cur_member) {
06117 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
06118 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
06119 }
06120 } else {
06121
06122 ast_db_del(pm_family, pm_queue->name);
06123 }
06124
06125 ast_free(value);
06126 }
06127
06128
06129
06130
06131
06132
06133
06134 static int remove_from_queue(const char *queuename, const char *interface)
06135 {
06136 struct call_queue *q, tmpq = {
06137 .name = queuename,
06138 };
06139 struct member *mem, tmpmem;
06140 int res = RES_NOSUCHQUEUE;
06141
06142 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
06143 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
06144 ao2_lock(q);
06145 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
06146
06147
06148 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) {
06149 update_realtime_member_field(mem, q->name, "penalty", "-1");
06150 } else if (!mem->dynamic) {
06151 ao2_ref(mem, -1);
06152 ao2_unlock(q);
06153 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
06154 return RES_NOT_DYNAMIC;
06155 }
06156
06157
06158
06159
06160
06161
06162
06163
06164
06165
06166
06167
06168
06169
06170 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
06171 "Queue: %s\r\n"
06172 "Location: %s\r\n"
06173 "MemberName: %s\r\n",
06174 q->name, mem->interface, mem->membername);
06175 member_remove_from_queue(q, mem);
06176 ao2_ref(mem, -1);
06177
06178 if (queue_persistent_members) {
06179 dump_queue_members(q);
06180 }
06181
06182 if (!num_available_members(q)) {
06183 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
06184 }
06185
06186 res = RES_OKAY;
06187 } else {
06188 res = RES_EXISTS;
06189 }
06190 ao2_unlock(q);
06191 queue_t_unref(q, "Expiring temporary reference");
06192 }
06193
06194 return res;
06195 }
06196
06197
06198
06199
06200
06201
06202
06203
06204 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
06205 {
06206 struct call_queue *q;
06207 struct member *new_member, *old_member;
06208 int res = RES_NOSUCHQUEUE;
06209
06210
06211
06212 if (!(q = find_load_queue_rt_friendly(queuename))) {
06213 return res;
06214 }
06215
06216 ao2_lock(q);
06217 if ((old_member = interface_exists(q, interface)) == NULL) {
06218 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) {
06219 new_member->ringinuse = q->ringinuse;
06220 new_member->dynamic = 1;
06221 member_add_to_queue(q, new_member);
06222
06223
06224
06225
06226
06227
06228
06229
06230
06231
06232
06233
06234
06235
06236
06237
06238
06239
06240
06241
06242
06243 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
06244 "Queue: %s\r\n"
06245 "Location: %s\r\n"
06246 "MemberName: %s\r\n"
06247 "StateInterface: %s\r\n"
06248 "Membership: %s\r\n"
06249 "Penalty: %d\r\n"
06250 "CallsTaken: %d\r\n"
06251 "LastCall: %d\r\n"
06252 "Status: %d\r\n"
06253 "Paused: %d\r\n",
06254 q->name, new_member->interface, new_member->membername, state_interface,
06255 "dynamic",
06256 new_member->penalty, new_member->calls, (int) new_member->lastcall,
06257 new_member->status, new_member->paused);
06258
06259 if (is_member_available(q, new_member)) {
06260 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
06261 }
06262
06263 ao2_ref(new_member, -1);
06264 new_member = NULL;
06265
06266 if (dump) {
06267 dump_queue_members(q);
06268 }
06269
06270 res = RES_OKAY;
06271 } else {
06272 res = RES_OUTOFMEMORY;
06273 }
06274 } else {
06275 ao2_ref(old_member, -1);
06276 res = RES_EXISTS;
06277 }
06278 ao2_unlock(q);
06279 queue_t_unref(q, "Expiring temporary reference");
06280
06281 return res;
06282 }
06283
06284 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
06285 {
06286 int found = 0;
06287 struct call_queue *q;
06288 struct member *mem;
06289 struct ao2_iterator queue_iter;
06290 int failed;
06291
06292
06293
06294 if (ast_strlen_zero(queuename))
06295 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
06296
06297 queue_iter = ao2_iterator_init(queues, 0);
06298 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
06299 ao2_lock(q);
06300 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
06301 if ((mem = interface_exists(q, interface))) {
06302 if (mem->paused == paused) {
06303 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
06304 }
06305
06306 failed = 0;
06307 if (mem->realtime) {
06308 failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
06309 }
06310
06311 if (failed) {
06312 ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
06313 ao2_ref(mem, -1);
06314 ao2_unlock(q);
06315 queue_t_unref(q, "Done with iterator");
06316 continue;
06317 }
06318 found++;
06319 mem->paused = paused;
06320
06321 if (queue_persistent_members) {
06322 dump_queue_members(q);
06323 }
06324
06325 if (is_member_available(q, mem)) {
06326 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
06327 } else if (!num_available_members(q)) {
06328 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
06329 }
06330
06331 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
06332
06333 if (!ast_strlen_zero(reason)) {
06334
06335
06336
06337
06338
06339
06340
06341
06342
06343
06344
06345
06346
06347
06348
06349
06350
06351
06352 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
06353 "Queue: %s\r\n"
06354 "Location: %s\r\n"
06355 "MemberName: %s\r\n"
06356 "Paused: %d\r\n"
06357 "Reason: %s\r\n",
06358 q->name, mem->interface, mem->membername, paused, reason);
06359 } else {
06360
06361
06362
06363
06364
06365
06366
06367
06368
06369
06370
06371
06372
06373
06374
06375 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
06376 "Queue: %s\r\n"
06377 "Location: %s\r\n"
06378 "MemberName: %s\r\n"
06379 "Paused: %d\r\n",
06380 q->name, mem->interface, mem->membername, paused);
06381 }
06382 ao2_ref(mem, -1);
06383 }
06384 }
06385
06386 if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
06387 ao2_unlock(q);
06388 queue_t_unref(q, "Done with iterator");
06389 break;
06390 }
06391
06392 ao2_unlock(q);
06393 queue_t_unref(q, "Done with iterator");
06394 }
06395 ao2_iterator_destroy(&queue_iter);
06396
06397 return found ? RESULT_SUCCESS : RESULT_FAILURE;
06398 }
06399
06400
06401
06402
06403
06404
06405
06406
06407
06408
06409 static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
06410 {
06411 struct member *mem;
06412 int foundinterface = 0;
06413 char rtpenalty[80];
06414
06415 ao2_lock(q);
06416 if ((mem = interface_exists(q, interface))) {
06417 foundinterface++;
06418 if (!mem->realtime) {
06419 mem->penalty = penalty;
06420 } else {
06421 sprintf(rtpenalty, "%i", penalty);
06422 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
06423 }
06424 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
06425
06426
06427
06428
06429
06430
06431
06432
06433
06434
06435
06436
06437
06438 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
06439 "Queue: %s\r\n"
06440 "Location: %s\r\n"
06441 "Penalty: %d\r\n",
06442 q->name, mem->interface, penalty);
06443 ao2_ref(mem, -1);
06444 }
06445 ao2_unlock(q);
06446
06447 return foundinterface;
06448 }
06449
06450 static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
06451 {
06452 struct member *mem;
06453 int foundinterface = 0;
06454 char rtringinuse[80];
06455
06456 ao2_lock(q);
06457 if ((mem = interface_exists(q, interface))) {
06458 foundinterface++;
06459 if (!mem->realtime) {
06460 mem->ringinuse = ringinuse;
06461 } else {
06462 sprintf(rtringinuse, "%i", ringinuse);
06463 update_realtime_member_field(mem, q->name, realtime_ringinuse_field, rtringinuse);
06464 }
06465 ast_queue_log(q->name, "NONE", interface, "RINGINUSE", "%d", ringinuse);
06466
06467
06468
06469
06470
06471
06472
06473
06474
06475
06476
06477
06478
06479
06480
06481
06482
06483
06484 manager_event(EVENT_FLAG_AGENT, "QueueMemberRinginuse",
06485 "Queue: %s\r\n"
06486 "Location: %s\r\n"
06487 "Ringinuse: %d\r\n",
06488 q->name, mem->interface, ringinuse);
06489 ao2_ref(mem, -1);
06490 }
06491 ao2_unlock(q);
06492
06493 return foundinterface;
06494 }
06495
06496 static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
06497 {
06498 switch(property) {
06499 case MEMBER_PENALTY:
06500 return set_member_penalty_help_members(q, interface, value);
06501
06502 case MEMBER_RINGINUSE:
06503 return set_member_ringinuse_help_members(q, interface, value);
06504
06505 default:
06506 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
06507 return 0;
06508 }
06509 }
06510
06511
06512
06513
06514
06515
06516
06517
06518
06519 static int set_member_value(const char *queuename, const char *interface, int property, int value)
06520 {
06521 int foundinterface = 0, foundqueue = 0;
06522 struct call_queue *q;
06523 struct ast_config *queue_config = NULL;
06524 struct ao2_iterator queue_iter;
06525
06526
06527 switch (property) {
06528 case MEMBER_PENALTY:
06529 if (value < 0 && !negative_penalty_invalid) {
06530 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
06531 return RESULT_FAILURE;
06532 }
06533 }
06534
06535 if (ast_strlen_zero(queuename)) {
06536 if (ast_check_realtime("queues")) {
06537 char *name;
06538 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
06539 if (queue_config) {
06540 for (name = ast_category_browse(queue_config, NULL);
06541 !ast_strlen_zero(name);
06542 name = ast_category_browse(queue_config, name)) {
06543 if ((q = find_load_queue_rt_friendly(name))) {
06544 foundqueue++;
06545 foundinterface += set_member_value_help_members(q, interface, property, value);
06546 }
06547 }
06548 }
06549 }
06550
06551
06552 queue_iter = ao2_iterator_init(queues, 0);
06553 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06554 foundqueue++;
06555 foundinterface += set_member_value_help_members(q, interface, property, value);
06556 }
06557 ao2_iterator_destroy(&queue_iter);
06558 } else {
06559 if ((q = find_load_queue_rt_friendly(queuename))) {
06560 foundqueue++;
06561 foundinterface += set_member_value_help_members(q, interface, property, value);
06562 }
06563 }
06564
06565 if (foundinterface) {
06566 return RESULT_SUCCESS;
06567 } else if (!foundqueue) {
06568 ast_log (LOG_ERROR, "Invalid queuename\n");
06569 } else {
06570 ast_log (LOG_ERROR, "Invalid interface\n");
06571 }
06572
06573 return RESULT_FAILURE;
06574 }
06575
06576
06577
06578
06579 static int get_member_penalty(char *queuename, char *interface)
06580 {
06581 int foundqueue = 0, penalty;
06582 struct call_queue *q, tmpq = {
06583 .name = queuename,
06584 };
06585 struct member *mem;
06586
06587 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
06588 foundqueue = 1;
06589 ao2_lock(q);
06590 if ((mem = interface_exists(q, interface))) {
06591 penalty = mem->penalty;
06592 ao2_ref(mem, -1);
06593 ao2_unlock(q);
06594 queue_t_unref(q, "Search complete");
06595 return penalty;
06596 }
06597 ao2_unlock(q);
06598 queue_t_unref(q, "Search complete");
06599 }
06600
06601
06602 if (foundqueue) {
06603 ast_log (LOG_ERROR, "Invalid queuename\n");
06604 } else {
06605 ast_log (LOG_ERROR, "Invalid interface\n");
06606 }
06607
06608 return RESULT_FAILURE;
06609 }
06610
06611
06612 static void reload_queue_members(void)
06613 {
06614 char *cur_ptr;
06615 const char *queue_name;
06616 char *member;
06617 char *interface;
06618 char *membername = NULL;
06619 char *state_interface;
06620 char *penalty_tok;
06621 int penalty = 0;
06622 char *paused_tok;
06623 int paused = 0;
06624 struct ast_db_entry *db_tree;
06625 struct ast_db_entry *entry;
06626 struct call_queue *cur_queue;
06627 char *queue_data;
06628
06629
06630 db_tree = ast_db_gettree(pm_family, NULL);
06631 for (entry = db_tree; entry; entry = entry->next) {
06632
06633 queue_name = entry->key + strlen(pm_family) + 2;
06634
06635 {
06636 struct call_queue tmpq = {
06637 .name = queue_name,
06638 };
06639 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
06640 }
06641
06642 if (!cur_queue) {
06643 cur_queue = find_load_queue_rt_friendly(queue_name);
06644 }
06645
06646 if (!cur_queue) {
06647
06648
06649 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
06650 ast_db_del(pm_family, queue_name);
06651 continue;
06652 }
06653
06654 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
06655 queue_t_unref(cur_queue, "Expire reload reference");
06656 continue;
06657 }
06658
06659 cur_ptr = queue_data;
06660 while ((member = strsep(&cur_ptr, ",|"))) {
06661 if (ast_strlen_zero(member)) {
06662 continue;
06663 }
06664
06665 interface = strsep(&member, ";");
06666 penalty_tok = strsep(&member, ";");
06667 paused_tok = strsep(&member, ";");
06668 membername = strsep(&member, ";");
06669 state_interface = strsep(&member, ";");
06670
06671 if (!penalty_tok) {
06672 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
06673 break;
06674 }
06675 penalty = strtol(penalty_tok, NULL, 10);
06676 if (errno == ERANGE) {
06677 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
06678 break;
06679 }
06680
06681 if (!paused_tok) {
06682 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
06683 break;
06684 }
06685 paused = strtol(paused_tok, NULL, 10);
06686 if ((errno == ERANGE) || paused < 0 || paused > 1) {
06687 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
06688 break;
06689 }
06690
06691 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
06692
06693 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
06694 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
06695 break;
06696 }
06697 }
06698 queue_t_unref(cur_queue, "Expire reload reference");
06699 ast_free(queue_data);
06700 }
06701
06702 if (db_tree) {
06703 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
06704 ast_db_freetree(db_tree);
06705 }
06706 }
06707
06708
06709 static int pqm_exec(struct ast_channel *chan, const char *data)
06710 {
06711 char *parse;
06712 AST_DECLARE_APP_ARGS(args,
06713 AST_APP_ARG(queuename);
06714 AST_APP_ARG(interface);
06715 AST_APP_ARG(options);
06716 AST_APP_ARG(reason);
06717 );
06718
06719 if (ast_strlen_zero(data)) {
06720 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
06721 return -1;
06722 }
06723
06724 parse = ast_strdupa(data);
06725
06726 AST_STANDARD_APP_ARGS(args, parse);
06727
06728 if (ast_strlen_zero(args.interface)) {
06729 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
06730 return -1;
06731 }
06732
06733 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
06734 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
06735 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
06736 return 0;
06737 }
06738
06739 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
06740
06741 return 0;
06742 }
06743
06744
06745 static int upqm_exec(struct ast_channel *chan, const char *data)
06746 {
06747 char *parse;
06748 AST_DECLARE_APP_ARGS(args,
06749 AST_APP_ARG(queuename);
06750 AST_APP_ARG(interface);
06751 AST_APP_ARG(options);
06752 AST_APP_ARG(reason);
06753 );
06754
06755 if (ast_strlen_zero(data)) {
06756 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
06757 return -1;
06758 }
06759
06760 parse = ast_strdupa(data);
06761
06762 AST_STANDARD_APP_ARGS(args, parse);
06763
06764 if (ast_strlen_zero(args.interface)) {
06765 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
06766 return -1;
06767 }
06768
06769 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
06770 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
06771 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
06772 return 0;
06773 }
06774
06775 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
06776
06777 return 0;
06778 }
06779
06780
06781 static int rqm_exec(struct ast_channel *chan, const char *data)
06782 {
06783 int res=-1;
06784 char *parse, *temppos = NULL;
06785 struct member *mem = NULL;
06786
06787 AST_DECLARE_APP_ARGS(args,
06788 AST_APP_ARG(queuename);
06789 AST_APP_ARG(interface);
06790 );
06791
06792
06793 if (ast_strlen_zero(data)) {
06794 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
06795 return -1;
06796 }
06797
06798 parse = ast_strdupa(data);
06799
06800 AST_STANDARD_APP_ARGS(args, parse);
06801
06802 if (ast_strlen_zero(args.interface)) {
06803 args.interface = ast_strdupa(ast_channel_name(chan));
06804 temppos = strrchr(args.interface, '-');
06805 if (temppos) {
06806 *temppos = '\0';
06807 }
06808 }
06809
06810 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
06811
06812 if (log_membername_as_agent) {
06813 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
06814 }
06815
06816 switch (remove_from_queue(args.queuename, args.interface)) {
06817 case RES_OKAY:
06818 if (!mem || ast_strlen_zero(mem->membername)) {
06819 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
06820 } else {
06821 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
06822 }
06823 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
06824 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
06825 res = 0;
06826 break;
06827 case RES_EXISTS:
06828 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
06829 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
06830 res = 0;
06831 break;
06832 case RES_NOSUCHQUEUE:
06833 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
06834 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
06835 res = 0;
06836 break;
06837 case RES_NOT_DYNAMIC:
06838 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
06839 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
06840 res = 0;
06841 break;
06842 }
06843
06844 if (mem) {
06845 ao2_ref(mem, -1);
06846 }
06847
06848 return res;
06849 }
06850
06851
06852 static int aqm_exec(struct ast_channel *chan, const char *data)
06853 {
06854 int res=-1;
06855 char *parse, *temppos = NULL;
06856 AST_DECLARE_APP_ARGS(args,
06857 AST_APP_ARG(queuename);
06858 AST_APP_ARG(interface);
06859 AST_APP_ARG(penalty);
06860 AST_APP_ARG(options);
06861 AST_APP_ARG(membername);
06862 AST_APP_ARG(state_interface);
06863 );
06864 int penalty = 0;
06865
06866 if (ast_strlen_zero(data)) {
06867 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
06868 return -1;
06869 }
06870
06871 parse = ast_strdupa(data);
06872
06873 AST_STANDARD_APP_ARGS(args, parse);
06874
06875 if (ast_strlen_zero(args.interface)) {
06876 args.interface = ast_strdupa(ast_channel_name(chan));
06877 temppos = strrchr(args.interface, '-');
06878 if (temppos) {
06879 *temppos = '\0';
06880 }
06881 }
06882
06883 if (!ast_strlen_zero(args.penalty)) {
06884 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
06885 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
06886 penalty = 0;
06887 }
06888 }
06889
06890 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
06891 case RES_OKAY:
06892 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
06893 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
06894 } else {
06895 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
06896 }
06897 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
06898 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
06899 res = 0;
06900 break;
06901 case RES_EXISTS:
06902 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
06903 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
06904 res = 0;
06905 break;
06906 case RES_NOSUCHQUEUE:
06907 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
06908 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
06909 res = 0;
06910 break;
06911 case RES_OUTOFMEMORY:
06912 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
06913 break;
06914 }
06915
06916 return res;
06917 }
06918
06919
06920 static int ql_exec(struct ast_channel *chan, const char *data)
06921 {
06922 char *parse;
06923
06924 AST_DECLARE_APP_ARGS(args,
06925 AST_APP_ARG(queuename);
06926 AST_APP_ARG(uniqueid);
06927 AST_APP_ARG(membername);
06928 AST_APP_ARG(event);
06929 AST_APP_ARG(params);
06930 );
06931
06932 if (ast_strlen_zero(data)) {
06933 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
06934 return -1;
06935 }
06936
06937 parse = ast_strdupa(data);
06938
06939 AST_STANDARD_APP_ARGS(args, parse);
06940
06941 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
06942 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
06943 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
06944 return -1;
06945 }
06946
06947 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
06948 "%s", args.params ? args.params : "");
06949
06950 return 0;
06951 }
06952
06953
06954 static void copy_rules(struct queue_ent *qe, const char *rulename)
06955 {
06956 struct penalty_rule *pr_iter;
06957 struct rule_list *rl_iter;
06958 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
06959 AST_LIST_LOCK(&rule_lists);
06960 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
06961 if (!strcasecmp(rl_iter->name, tmp)) {
06962 break;
06963 }
06964 }
06965 if (rl_iter) {
06966 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
06967 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
06968 if (!new_pr) {
06969 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
06970 break;
06971 }
06972 new_pr->time = pr_iter->time;
06973 new_pr->max_value = pr_iter->max_value;
06974 new_pr->min_value = pr_iter->min_value;
06975 new_pr->max_relative = pr_iter->max_relative;
06976 new_pr->min_relative = pr_iter->min_relative;
06977 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
06978 }
06979 }
06980 AST_LIST_UNLOCK(&rule_lists);
06981 }
06982
06983
06984
06985
06986
06987
06988
06989
06990
06991
06992
06993
06994
06995 static int queue_exec(struct ast_channel *chan, const char *data)
06996 {
06997 int res=-1;
06998 int ringing=0;
06999 const char *user_priority;
07000 const char *max_penalty_str;
07001 const char *min_penalty_str;
07002 int prio;
07003 int qcontinue = 0;
07004 int max_penalty, min_penalty;
07005 enum queue_result reason = QUEUE_UNKNOWN;
07006
07007 int tries = 0;
07008 int noption = 0;
07009 char *parse;
07010 int makeannouncement = 0;
07011 int position = 0;
07012 AST_DECLARE_APP_ARGS(args,
07013 AST_APP_ARG(queuename);
07014 AST_APP_ARG(options);
07015 AST_APP_ARG(url);
07016 AST_APP_ARG(announceoverride);
07017 AST_APP_ARG(queuetimeoutstr);
07018 AST_APP_ARG(agi);
07019 AST_APP_ARG(macro);
07020 AST_APP_ARG(gosub);
07021 AST_APP_ARG(rule);
07022 AST_APP_ARG(position);
07023 );
07024
07025 struct queue_ent qe = { 0 };
07026 struct ast_flags opts = { 0, };
07027 char *opt_args[OPT_ARG_ARRAY_SIZE];
07028
07029 if (ast_strlen_zero(data)) {
07030 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
07031 return -1;
07032 }
07033
07034 parse = ast_strdupa(data);
07035 AST_STANDARD_APP_ARGS(args, parse);
07036
07037 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, macro: %s, gosub: %s, rule: %s, position: %s\n",
07038 args.queuename,
07039 S_OR(args.options, ""),
07040 S_OR(args.url, ""),
07041 S_OR(args.announceoverride, ""),
07042 S_OR(args.queuetimeoutstr, ""),
07043 S_OR(args.agi, ""),
07044 S_OR(args.macro, ""),
07045 S_OR(args.gosub, ""),
07046 S_OR(args.rule, ""),
07047 S_OR(args.position, ""));
07048
07049 if (!ast_strlen_zero(args.options)) {
07050 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
07051 }
07052
07053
07054 qe.start = time(NULL);
07055
07056
07057 if (!ast_strlen_zero(args.queuetimeoutstr)) {
07058 qe.expire = qe.start + atoi(args.queuetimeoutstr);
07059 } else {
07060 qe.expire = 0;
07061 }
07062
07063
07064 ast_channel_lock(chan);
07065 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
07066 if (user_priority) {
07067 if (sscanf(user_priority, "%30d", &prio) == 1) {
07068 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
07069 } else {
07070 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
07071 user_priority, ast_channel_name(chan));
07072 prio = 0;
07073 }
07074 } else {
07075 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
07076 prio = 0;
07077 }
07078
07079
07080
07081 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
07082 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
07083 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
07084 } else {
07085 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
07086 max_penalty_str, ast_channel_name(chan));
07087 max_penalty = INT_MAX;
07088 }
07089 } else {
07090 max_penalty = INT_MAX;
07091 }
07092
07093 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
07094 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
07095 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
07096 } else {
07097 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
07098 min_penalty_str, ast_channel_name(chan));
07099 min_penalty = INT_MAX;
07100 }
07101 } else {
07102 min_penalty = INT_MAX;
07103 }
07104 ast_channel_unlock(chan);
07105
07106 if (ast_test_flag(&opts, OPT_RINGING)) {
07107 ringing = 1;
07108 }
07109
07110 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
07111 qe.ring_when_ringing = 1;
07112 }
07113
07114 if (ast_test_flag(&opts, OPT_GO_ON)) {
07115 qcontinue = 1;
07116 }
07117
07118 if (args.position) {
07119 position = atoi(args.position);
07120 if (position < 0) {
07121 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
07122 position = 0;
07123 }
07124 }
07125
07126 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
07127 args.queuename, (long)qe.expire, prio);
07128
07129 qe.chan = chan;
07130 qe.prio = prio;
07131 qe.max_penalty = max_penalty;
07132 qe.min_penalty = min_penalty;
07133 qe.last_pos_said = 0;
07134 qe.last_pos = 0;
07135 qe.last_periodic_announce_time = time(NULL);
07136 qe.last_periodic_announce_sound = 0;
07137 qe.valid_digits = 0;
07138 if (join_queue(args.queuename, &qe, &reason, position)) {
07139 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
07140 set_queue_result(chan, reason);
07141 return 0;
07142 }
07143 ast_assert(qe.parent != NULL);
07144
07145 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
07146 S_OR(args.url, ""),
07147 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
07148 qe.opos);
07149 copy_rules(&qe, args.rule);
07150 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
07151 check_turns:
07152 if (ringing) {
07153 ast_indicate(chan, AST_CONTROL_RINGING);
07154 } else {
07155 ast_moh_start(chan, qe.moh, NULL);
07156 }
07157
07158
07159 res = wait_our_turn(&qe, ringing, &reason);
07160 if (res) {
07161 goto stop;
07162 }
07163
07164 makeannouncement = 0;
07165
07166 for (;;) {
07167
07168
07169
07170
07171
07172
07173 if (qe.expire && (time(NULL) >= qe.expire)) {
07174 record_abandoned(&qe);
07175 reason = QUEUE_TIMEOUT;
07176 res = 0;
07177 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
07178 qe.pos, qe.opos, (long) time(NULL) - qe.start);
07179 break;
07180 }
07181
07182 if (makeannouncement) {
07183
07184 if (qe.parent->announcefrequency)
07185 if ((res = say_position(&qe,ringing)))
07186 goto stop;
07187 }
07188 makeannouncement = 1;
07189
07190
07191 if (qe.parent->periodicannouncefrequency) {
07192 if ((res = say_periodic_announcement(&qe,ringing))) {
07193 goto stop;
07194 }
07195 }
07196
07197
07198 if (qe.expire && (time(NULL) >= qe.expire)) {
07199 record_abandoned(&qe);
07200 reason = QUEUE_TIMEOUT;
07201 res = 0;
07202 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
07203 break;
07204 }
07205
07206
07207 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
07208 update_qe_rule(&qe);
07209 }
07210
07211
07212 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
07213 if (res) {
07214 goto stop;
07215 }
07216
07217 if (qe.parent->leavewhenempty) {
07218 int status = 0;
07219 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty, 0))) {
07220 record_abandoned(&qe);
07221 reason = QUEUE_LEAVEEMPTY;
07222 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
07223 res = 0;
07224 break;
07225 }
07226 }
07227
07228
07229 if (noption && tries >= ao2_container_count(qe.parent->members)) {
07230 ast_verb(3, "Exiting on time-out cycle\n");
07231 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
07232 record_abandoned(&qe);
07233 reason = QUEUE_TIMEOUT;
07234 res = 0;
07235 break;
07236 }
07237
07238
07239
07240 if (qe.expire && (time(NULL) >= qe.expire)) {
07241 record_abandoned(&qe);
07242 reason = QUEUE_TIMEOUT;
07243 res = 0;
07244 ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
07245 break;
07246 }
07247
07248
07249 update_realtime_members(qe.parent);
07250
07251 res = wait_a_bit(&qe);
07252 if (res) {
07253 goto stop;
07254 }
07255
07256
07257
07258
07259
07260 if (!is_our_turn(&qe)) {
07261 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
07262 goto check_turns;
07263 }
07264 }
07265
07266 stop:
07267 if (res) {
07268 if (res < 0) {
07269 if (!qe.handled) {
07270 record_abandoned(&qe);
07271 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
07272 "%d|%d|%ld", qe.pos, qe.opos,
07273 (long) time(NULL) - qe.start);
07274 res = -1;
07275 } else if (qcontinue) {
07276 reason = QUEUE_CONTINUE;
07277 res = 0;
07278 }
07279 } else if (qe.valid_digits) {
07280 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
07281 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) time(NULL) - qe.start);
07282 }
07283 }
07284
07285
07286 if (res >= 0) {
07287 res = 0;
07288 if (ringing) {
07289 ast_indicate(chan, -1);
07290 } else {
07291 ast_moh_stop(chan);
07292 }
07293 ast_stopstream(chan);
07294 }
07295
07296 set_queue_variables(qe.parent, qe.chan);
07297
07298 leave_queue(&qe);
07299 if (reason != QUEUE_UNKNOWN)
07300 set_queue_result(chan, reason);
07301
07302
07303
07304
07305
07306
07307
07308 qe.parent = queue_unref(qe.parent);
07309
07310 return res;
07311 }
07312
07313
07314
07315
07316
07317
07318 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07319 {
07320 int res = -1;
07321 struct call_queue *q, tmpq = {
07322 .name = data,
07323 };
07324
07325 char interfacevar[256] = "";
07326 float sl = 0;
07327
07328 if (ast_strlen_zero(data)) {
07329 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
07330 return -1;
07331 }
07332
07333 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
07334 ao2_lock(q);
07335 if (q->setqueuevar) {
07336 sl = 0;
07337 res = 0;
07338
07339 if (q->callscompleted > 0) {
07340 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
07341 }
07342
07343 snprintf(interfacevar, sizeof(interfacevar),
07344 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
07345 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
07346
07347 pbx_builtin_setvar_multiple(chan, interfacevar);
07348 }
07349
07350 ao2_unlock(q);
07351 queue_t_unref(q, "Done with QUEUE() function");
07352 } else {
07353 ast_log(LOG_WARNING, "queue %s was not found\n", data);
07354 }
07355
07356 snprintf(buf, len, "%d", res);
07357
07358 return 0;
07359 }
07360
07361
07362
07363
07364
07365 static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07366 {
07367 struct call_queue *q;
07368
07369 buf[0] = '\0';
07370
07371 if (ast_strlen_zero(data)) {
07372 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
07373 return -1;
07374 }
07375 q = find_load_queue_rt_friendly(data);
07376 snprintf(buf, len, "%d", q != NULL? 1 : 0);
07377 if (q) {
07378 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
07379 }
07380
07381 return 0;
07382 }
07383
07384
07385
07386
07387
07388
07389
07390 static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07391 {
07392 int count = 0;
07393 struct member *m;
07394 struct ao2_iterator mem_iter;
07395 struct call_queue *q;
07396
07397 AST_DECLARE_APP_ARGS(args,
07398 AST_APP_ARG(queuename);
07399 AST_APP_ARG(option);
07400 AST_APP_ARG(interface);
07401 );
07402
07403 buf[0] = '\0';
07404
07405 if (ast_strlen_zero(data)) {
07406 ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd);
07407 return -1;
07408 }
07409
07410 AST_STANDARD_APP_ARGS(args, data);
07411
07412 if (args.argc < 2) {
07413 ast_log(LOG_ERROR, "Missing required argument. %s(<queuename>,<option>[<interface>])\n", cmd);
07414 return -1;
07415 }
07416
07417 if ((q = find_load_queue_rt_friendly(args.queuename))) {
07418 ao2_lock(q);
07419 if (!strcasecmp(args.option, "logged")) {
07420 mem_iter = ao2_iterator_init(q->members, 0);
07421 while ((m = ao2_iterator_next(&mem_iter))) {
07422
07423 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
07424 count++;
07425 }
07426 ao2_ref(m, -1);
07427 }
07428 ao2_iterator_destroy(&mem_iter);
07429 } else if (!strcasecmp(args.option, "free")) {
07430 mem_iter = ao2_iterator_init(q->members, 0);
07431 while ((m = ao2_iterator_next(&mem_iter))) {
07432
07433 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
07434 count++;
07435 }
07436 ao2_ref(m, -1);
07437 }
07438 ao2_iterator_destroy(&mem_iter);
07439 } else if (!strcasecmp(args.option, "ready")) {
07440 time_t now;
07441 time(&now);
07442 mem_iter = ao2_iterator_init(q->members, 0);
07443 while ((m = ao2_iterator_next(&mem_iter))) {
07444
07445 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
07446 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
07447 count++;
07448 }
07449 ao2_ref(m, -1);
07450 }
07451 ao2_iterator_destroy(&mem_iter);
07452 } else if (!strcasecmp(args.option, "count") || ast_strlen_zero(args.option)) {
07453 count = ao2_container_count(q->members);
07454 } else if (!strcasecmp(args.option, "penalty") && !ast_strlen_zero(args.interface) &&
07455 ((m = interface_exists(q, args.interface)))) {
07456 count = m->penalty;
07457 ao2_ref(m, -1);
07458 } else if (!strcasecmp(args.option, "paused") && !ast_strlen_zero(args.interface) &&
07459 ((m = interface_exists(q, args.interface)))) {
07460 count = m->paused;
07461 ao2_ref(m, -1);
07462 } else if ( (!strcasecmp(args.option, "ignorebusy") || !strcasecmp(args.option, "ringinuse")) &&
07463 !ast_strlen_zero(args.interface) &&
07464 ((m = interface_exists(q, args.interface)))) {
07465 count = m->ringinuse;
07466 ao2_ref(m, -1);
07467 } else if (!ast_strlen_zero(args.interface)) {
07468 ast_log(LOG_ERROR, "Queue member interface %s not in queue %s\n",
07469 args.interface, args.queuename);
07470 } else {
07471 ast_log(LOG_ERROR, "Unknown option %s provided to %s, valid values are: "
07472 "logged, free, ready, count, penalty, paused, ringinuse\n", args.option, cmd);
07473 }
07474 ao2_unlock(q);
07475 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
07476 } else {
07477 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
07478 }
07479
07480 snprintf(buf, len, "%d", count);
07481
07482 return 0;
07483 }
07484
07485
07486 static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
07487 {
07488 int memvalue;
07489 struct call_queue *q;
07490 struct member *m;
07491 char rtvalue[80];
07492
07493 AST_DECLARE_APP_ARGS(args,
07494 AST_APP_ARG(queuename);
07495 AST_APP_ARG(option);
07496 AST_APP_ARG(interface);
07497 );
07498
07499 if (ast_strlen_zero(data)) {
07500 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER(<queuename>,<option>,<interface>)\n");
07501 return -1;
07502 }
07503
07504 AST_STANDARD_APP_ARGS(args, data);
07505
07506 if (args.argc < 3) {
07507 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
07508 return -1;
07509 }
07510
07511 if (ast_strlen_zero(args.interface) && ast_strlen_zero(args.option)) {
07512 ast_log (LOG_ERROR, "<interface> and <option> parameter's can't be null\n");
07513 return -1;
07514 }
07515
07516 memvalue = atoi(value);
07517 if (!strcasecmp(args.option, "penalty")) {
07518
07519 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
07520 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
07521 return -1;
07522 }
07523 } else if ((q = find_load_queue_rt_friendly(args.queuename))) {
07524 ao2_lock(q);
07525 if ((m = interface_exists(q, args.interface))) {
07526 sprintf(rtvalue, "%s",(memvalue <= 0) ? "0" : "1");
07527 if (!strcasecmp(args.option, "paused")) {
07528 if (m->realtime) {
07529 update_realtime_member_field(m, q->name, args.option, rtvalue);
07530 } else {
07531 m->paused = (memvalue <= 0) ? 0 : 1;
07532 }
07533 } else if ((!strcasecmp(args.option, "ignorebusy")) || (!strcasecmp(args.option, "ringinuse"))) {
07534 if (m->realtime) {
07535 update_realtime_member_field(m, q->name, args.option, rtvalue);
07536 } else {
07537 m->ringinuse = (memvalue <= 0) ? 0 : 1;
07538 }
07539 } else {
07540 ast_log(LOG_ERROR, "Invalid option, only penalty , paused or ringinuse/ignorebusy are valid\n");
07541 ao2_ref(m, -1);
07542 ao2_unlock(q);
07543 ao2_ref(q, -1);
07544 return -1;
07545 }
07546 ao2_ref(m, -1);
07547 } else {
07548 ao2_unlock(q);
07549 ao2_ref(q, -1);
07550 ast_log(LOG_ERROR, "Invalid interface for queue\n");
07551 return -1;
07552 }
07553 ao2_unlock(q);
07554 ao2_ref(q, -1);
07555 } else {
07556 ast_log(LOG_ERROR, "Invalid queue\n");
07557 return -1;
07558 }
07559 return 0;
07560 }
07561
07562
07563
07564
07565
07566
07567 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07568 {
07569 int count = 0;
07570 struct member *m;
07571 struct call_queue *q;
07572 struct ao2_iterator mem_iter;
07573 static int depflag = 1;
07574
07575 if (depflag) {
07576 depflag = 0;
07577 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");
07578 }
07579
07580 if (ast_strlen_zero(data)) {
07581 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
07582 return -1;
07583 }
07584
07585 if ((q = find_load_queue_rt_friendly(data))) {
07586 ao2_lock(q);
07587 mem_iter = ao2_iterator_init(q->members, 0);
07588 while ((m = ao2_iterator_next(&mem_iter))) {
07589
07590 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
07591 count++;
07592 }
07593 ao2_ref(m, -1);
07594 }
07595 ao2_iterator_destroy(&mem_iter);
07596 ao2_unlock(q);
07597 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
07598 } else {
07599 ast_log(LOG_WARNING, "queue %s was not found\n", data);
07600 }
07601
07602 snprintf(buf, len, "%d", count);
07603
07604 return 0;
07605 }
07606
07607
07608 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07609 {
07610 int count = 0;
07611 struct call_queue *q, tmpq = {
07612 .name = data,
07613 };
07614 struct ast_variable *var = NULL;
07615
07616 buf[0] = '\0';
07617
07618 if (ast_strlen_zero(data)) {
07619 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
07620 return -1;
07621 }
07622
07623 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
07624 ao2_lock(q);
07625 count = q->count;
07626 ao2_unlock(q);
07627 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
07628 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
07629
07630
07631
07632
07633 count = 0;
07634 ast_variables_destroy(var);
07635 } else {
07636 ast_log(LOG_WARNING, "queue %s was not found\n", data);
07637 }
07638
07639 snprintf(buf, len, "%d", count);
07640
07641 return 0;
07642 }
07643
07644
07645 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07646 {
07647 struct call_queue *q, tmpq = {
07648 .name = data,
07649 };
07650 struct member *m;
07651
07652
07653 buf[0] = '\0';
07654
07655 if (ast_strlen_zero(data)) {
07656 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
07657 return -1;
07658 }
07659
07660 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
07661 int buflen = 0, count = 0;
07662 struct ao2_iterator mem_iter;
07663
07664 ao2_lock(q);
07665 mem_iter = ao2_iterator_init(q->members, 0);
07666 while ((m = ao2_iterator_next(&mem_iter))) {
07667
07668 if (count++) {
07669 strncat(buf + buflen, ",", len - buflen - 1);
07670 buflen++;
07671 }
07672 strncat(buf + buflen, m->interface, len - buflen - 1);
07673 buflen += strlen(m->interface);
07674
07675 if (buflen >= len - 2) {
07676 ao2_ref(m, -1);
07677 ast_log(LOG_WARNING, "Truncating list\n");
07678 break;
07679 }
07680 ao2_ref(m, -1);
07681 }
07682 ao2_iterator_destroy(&mem_iter);
07683 ao2_unlock(q);
07684 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
07685 } else
07686 ast_log(LOG_WARNING, "queue %s was not found\n", data);
07687
07688
07689 buf[len - 1] = '\0';
07690
07691 return 0;
07692 }
07693
07694
07695 static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
07696 {
07697 int penalty;
07698 AST_DECLARE_APP_ARGS(args,
07699 AST_APP_ARG(queuename);
07700 AST_APP_ARG(interface);
07701 );
07702
07703 buf[0] = '\0';
07704
07705 if (ast_strlen_zero(data)) {
07706 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
07707 return -1;
07708 }
07709
07710 AST_STANDARD_APP_ARGS(args, data);
07711
07712 if (args.argc < 2) {
07713 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
07714 return -1;
07715 }
07716
07717 penalty = get_member_penalty (args.queuename, args.interface);
07718
07719 if (penalty >= 0) {
07720 snprintf (buf, len, "%d", penalty);
07721 }
07722
07723 return 0;
07724 }
07725
07726
07727 static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
07728 {
07729 int penalty;
07730 AST_DECLARE_APP_ARGS(args,
07731 AST_APP_ARG(queuename);
07732 AST_APP_ARG(interface);
07733 );
07734
07735 if (ast_strlen_zero(data)) {
07736 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
07737 return -1;
07738 }
07739
07740 AST_STANDARD_APP_ARGS(args, data);
07741
07742 if (args.argc < 2) {
07743 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
07744 return -1;
07745 }
07746
07747 penalty = atoi(value);
07748
07749 if (ast_strlen_zero(args.interface)) {
07750 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
07751 return -1;
07752 }
07753
07754
07755 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
07756 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
07757 return -1;
07758 }
07759
07760 return 0;
07761 }
07762
07763 static struct ast_custom_function queueexists_function = {
07764 .name = "QUEUE_EXISTS",
07765 .read = queue_function_exists,
07766 };
07767
07768 static struct ast_custom_function queuevar_function = {
07769 .name = "QUEUE_VARIABLES",
07770 .read = queue_function_var,
07771 };
07772
07773 static struct ast_custom_function queuemembercount_function = {
07774 .name = "QUEUE_MEMBER",
07775 .read = queue_function_mem_read,
07776 .write = queue_function_mem_write,
07777 };
07778
07779 static struct ast_custom_function queuemembercount_dep = {
07780 .name = "QUEUE_MEMBER_COUNT",
07781 .read = queue_function_qac_dep,
07782 };
07783
07784 static struct ast_custom_function queuewaitingcount_function = {
07785 .name = "QUEUE_WAITING_COUNT",
07786 .read = queue_function_queuewaitingcount,
07787 };
07788
07789 static struct ast_custom_function queuememberlist_function = {
07790 .name = "QUEUE_MEMBER_LIST",
07791 .read = queue_function_queuememberlist,
07792 };
07793
07794 static struct ast_custom_function queuememberpenalty_function = {
07795 .name = "QUEUE_MEMBER_PENALTY",
07796 .read = queue_function_memberpenalty_read,
07797 .write = queue_function_memberpenalty_write,
07798 };
07799
07800
07801
07802
07803
07804
07805
07806 static int reload_queue_rules(int reload)
07807 {
07808 struct ast_config *cfg;
07809 struct rule_list *rl_iter, *new_rl;
07810 struct penalty_rule *pr_iter;
07811 char *rulecat = NULL;
07812 struct ast_variable *rulevar = NULL;
07813 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
07814
07815 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
07816 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
07817 return AST_MODULE_LOAD_SUCCESS;
07818 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
07819 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
07820 return AST_MODULE_LOAD_SUCCESS;
07821 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
07822 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
07823 return AST_MODULE_LOAD_SUCCESS;
07824 }
07825
07826 AST_LIST_LOCK(&rule_lists);
07827 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
07828 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
07829 ast_free(pr_iter);
07830 ast_free(rl_iter);
07831 }
07832 while ((rulecat = ast_category_browse(cfg, rulecat))) {
07833 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
07834 AST_LIST_UNLOCK(&rule_lists);
07835 ast_config_destroy(cfg);
07836 return AST_MODULE_LOAD_FAILURE;
07837 } else {
07838 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
07839 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
07840 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
07841 if(!strcasecmp(rulevar->name, "penaltychange"))
07842 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
07843 else
07844 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
07845 }
07846 }
07847 AST_LIST_UNLOCK(&rule_lists);
07848
07849 ast_config_destroy(cfg);
07850
07851 return AST_MODULE_LOAD_SUCCESS;
07852 }
07853
07854
07855 static void queue_set_global_params(struct ast_config *cfg)
07856 {
07857 const char *general_val = NULL;
07858 queue_persistent_members = 0;
07859 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
07860 queue_persistent_members = ast_true(general_val);
07861 }
07862 autofill_default = 0;
07863 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
07864 autofill_default = ast_true(general_val);
07865 }
07866 montype_default = 0;
07867 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
07868 if (!strcasecmp(general_val, "mixmonitor"))
07869 montype_default = 1;
07870 }
07871 update_cdr = 0;
07872 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) {
07873 update_cdr = ast_true(general_val);
07874 }
07875 shared_lastcall = 0;
07876 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
07877 shared_lastcall = ast_true(general_val);
07878 }
07879 negative_penalty_invalid = 0;
07880 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
07881 negative_penalty_invalid = ast_true(general_val);
07882 }
07883 log_membername_as_agent = 0;
07884 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
07885 log_membername_as_agent = ast_true(general_val);
07886 }
07887 }
07888
07889
07890
07891
07892
07893
07894
07895
07896
07897 static void reload_single_member(const char *memberdata, struct call_queue *q)
07898 {
07899 char *membername, *interface, *state_interface, *tmp;
07900 char *parse;
07901 struct member *cur, *newm;
07902 struct member tmpmem;
07903 int penalty;
07904 int ringinuse;
07905 AST_DECLARE_APP_ARGS(args,
07906 AST_APP_ARG(interface);
07907 AST_APP_ARG(penalty);
07908 AST_APP_ARG(membername);
07909 AST_APP_ARG(state_interface);
07910 AST_APP_ARG(ringinuse);
07911 );
07912
07913 if (ast_strlen_zero(memberdata)) {
07914 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
07915 return;
07916 }
07917
07918
07919 parse = ast_strdupa(memberdata);
07920
07921 AST_STANDARD_APP_ARGS(args, parse);
07922
07923 interface = args.interface;
07924 if (!ast_strlen_zero(args.penalty)) {
07925 tmp = args.penalty;
07926 ast_strip(tmp);
07927 penalty = atoi(tmp);
07928 if (penalty < 0) {
07929 penalty = 0;
07930 }
07931 } else {
07932 penalty = 0;
07933 }
07934
07935 if (!ast_strlen_zero(args.membername)) {
07936 membername = args.membername;
07937 ast_strip(membername);
07938 } else {
07939 membername = interface;
07940 }
07941
07942 if (!ast_strlen_zero(args.state_interface)) {
07943 state_interface = args.state_interface;
07944 ast_strip(state_interface);
07945 } else {
07946 state_interface = interface;
07947 }
07948
07949 if (!ast_strlen_zero(args.ringinuse)) {
07950 tmp = args.ringinuse;
07951 ast_strip(tmp);
07952 if (ast_true(tmp)) {
07953 ringinuse = 1;
07954 } else if (ast_false(tmp)) {
07955 ringinuse = 0;
07956 } else {
07957 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
07958 membername, q->name);
07959 ringinuse = q->ringinuse;
07960 }
07961 } else {
07962 ringinuse = q->ringinuse;
07963 }
07964
07965
07966 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
07967 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
07968
07969 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse))) {
07970 if (cur) {
07971
07972 ao2_lock(q->members);
07973 newm->queuepos = cur->queuepos;
07974 ao2_link(q->members, newm);
07975 ao2_unlink(q->members, cur);
07976 ao2_unlock(q->members);
07977 } else {
07978
07979 member_add_to_queue(q, newm);
07980 }
07981 ao2_ref(newm, -1);
07982 }
07983 newm = NULL;
07984
07985 if (cur) {
07986 ao2_ref(cur, -1);
07987 }
07988 }
07989
07990 static int mark_member_dead(void *obj, void *arg, int flags)
07991 {
07992 struct member *member = obj;
07993 if (!member->dynamic && !member->realtime) {
07994 member->delme = 1;
07995 }
07996 return 0;
07997 }
07998
07999 static int kill_dead_members(void *obj, void *arg, int flags)
08000 {
08001 struct member *member = obj;
08002
08003 if (!member->delme) {
08004 member->status = get_queue_member_status(member);
08005 return 0;
08006 } else {
08007 return CMP_MATCH;
08008 }
08009 }
08010
08011
08012
08013
08014
08015
08016
08017
08018
08019
08020
08021
08022 static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
08023 {
08024 int new;
08025 struct call_queue *q = NULL;
08026
08027 struct call_queue tmpq = {
08028 .name = queuename,
08029 };
08030 const char *tmpvar;
08031 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
08032 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
08033 int prev_weight = 0;
08034 struct ast_variable *var;
08035 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
08036 if (queue_reload) {
08037
08038 if (!(q = alloc_queue(queuename))) {
08039 return;
08040 }
08041 } else {
08042
08043
08044
08045 return;
08046 }
08047 new = 1;
08048 } else {
08049 new = 0;
08050 }
08051
08052 if (!new) {
08053 ao2_lock(q);
08054 prev_weight = q->weight ? 1 : 0;
08055 }
08056
08057 if (q->found) {
08058 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
08059 if (!new) {
08060
08061 ao2_unlock(q);
08062 }
08063 queue_t_unref(q, "We exist! Expiring temporary pointer");
08064 return;
08065 }
08066
08067
08068
08069
08070
08071 if (queue_reload) {
08072 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
08073 q->strategy = strat2int(tmpvar);
08074 if (q->strategy < 0) {
08075 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
08076 tmpvar, q->name);
08077 q->strategy = QUEUE_STRATEGY_RINGALL;
08078 }
08079 } else {
08080 q->strategy = QUEUE_STRATEGY_RINGALL;
08081 }
08082 init_queue(q);
08083 }
08084 if (member_reload) {
08085 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
08086 q->found = 1;
08087 }
08088
08089
08090 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
08091 if (queue_reload && strcasecmp(var->name, "member")) {
08092 queue_set_param(q, var->name, var->value, var->lineno, 1);
08093 }
08094 }
08095
08096
08097 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
08098 if (member_reload && !strcasecmp(var->name, "member")) {
08099 reload_single_member(var->value, q);
08100 }
08101 }
08102
08103
08104
08105
08106 if (!q->weight && prev_weight) {
08107 ast_atomic_fetchadd_int(&use_weight, -1);
08108 } else if (q->weight && !prev_weight) {
08109 ast_atomic_fetchadd_int(&use_weight, +1);
08110 }
08111
08112
08113 if (member_reload) {
08114 ao2_lock(q->members);
08115 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE, queue_delme_members_decrement_followers, q);
08116 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
08117 ao2_unlock(q->members);
08118 }
08119
08120 if (new) {
08121 queues_t_link(queues, q, "Add queue to container");
08122 } else {
08123 ao2_unlock(q);
08124 }
08125 queue_t_unref(q, "Expiring creation reference");
08126 }
08127
08128 static int remove_members_and_mark_unfound(void *obj, void *arg, int flags)
08129 {
08130 struct call_queue *q = obj;
08131 char *queuename = arg;
08132 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
08133 q->found = 0;
08134
08135 }
08136 return 0;
08137 }
08138
08139 static int mark_dead_and_unfound(void *obj, void *arg, int flags)
08140 {
08141 struct call_queue *q = obj;
08142 char *queuename = arg;
08143 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
08144 q->dead = 1;
08145 q->found = 0;
08146 }
08147 return 0;
08148 }
08149
08150 static int kill_dead_queues(void *obj, void *arg, int flags)
08151 {
08152 struct call_queue *q = obj;
08153 char *queuename = arg;
08154 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
08155 return CMP_MATCH;
08156 } else {
08157 return 0;
08158 }
08159 }
08160
08161
08162
08163
08164
08165
08166
08167
08168
08169
08170
08171
08172
08173 static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
08174 {
08175 struct ast_config *cfg;
08176 char *cat;
08177 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
08178 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
08179 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
08180
08181 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
08182 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
08183 return -1;
08184 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
08185 return 0;
08186 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
08187 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
08188 return -1;
08189 }
08190
08191
08192 ao2_lock(queues);
08193
08194
08195
08196
08197 if (queue_reload) {
08198 ao2_callback(queues, OBJ_NODATA | OBJ_NOLOCK, mark_dead_and_unfound, (char *) queuename);
08199 }
08200
08201 if (member_reload) {
08202 ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename);
08203 }
08204
08205
08206 cat = NULL;
08207 while ((cat = ast_category_browse(cfg, cat)) ) {
08208 if (!strcasecmp(cat, "general") && queue_reload) {
08209 queue_set_global_params(cfg);
08210 continue;
08211 }
08212 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
08213 reload_single_queue(cfg, mask, cat);
08214 }
08215
08216 ast_config_destroy(cfg);
08217
08218 if (queue_reload) {
08219 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_dead_queues, (char *) queuename);
08220 }
08221 ao2_unlock(queues);
08222 return 0;
08223 }
08224
08225
08226
08227
08228
08229
08230
08231
08232
08233
08234
08235
08236
08237
08238 static int clear_stats(const char *queuename)
08239 {
08240 struct call_queue *q;
08241 struct ao2_iterator queue_iter;
08242
08243 queue_iter = ao2_iterator_init(queues, 0);
08244 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
08245 ao2_lock(q);
08246 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
08247 clear_queue(q);
08248 ao2_unlock(q);
08249 queue_t_unref(q, "Done with iterator");
08250 }
08251 ao2_iterator_destroy(&queue_iter);
08252 return 0;
08253 }
08254
08255
08256
08257
08258
08259
08260
08261
08262
08263
08264
08265
08266
08267
08268 static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
08269 {
08270 int res = 0;
08271
08272 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
08273 res |= reload_queue_rules(reload);
08274 }
08275 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
08276 res |= clear_stats(queuename);
08277 }
08278 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
08279 res |= reload_queues(reload, mask, queuename);
08280 }
08281 return res;
08282 }
08283
08284
08285 static void do_print(struct mansession *s, int fd, const char *str)
08286 {
08287 if (s) {
08288 astman_append(s, "%s\r\n", str);
08289 } else {
08290 ast_cli(fd, "%s\n", str);
08291 }
08292 }
08293
08294
08295
08296
08297
08298
08299
08300 static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
08301 {
08302 struct call_queue *q;
08303 struct ast_str *out = ast_str_alloca(240);
08304 int found = 0;
08305 time_t now = time(NULL);
08306 struct ao2_iterator queue_iter;
08307 struct ao2_iterator mem_iter;
08308
08309 if (argc != 2 && argc != 3) {
08310 return CLI_SHOWUSAGE;
08311 }
08312
08313 if (argc == 3) {
08314 if ((q = find_load_queue_rt_friendly(argv[2]))) {
08315 queue_t_unref(q, "Done with temporary pointer");
08316 }
08317 } else if (ast_check_realtime("queues")) {
08318
08319
08320
08321 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
08322 char *queuename;
08323 if (cfg) {
08324 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
08325 if ((q = find_load_queue_rt_friendly(queuename))) {
08326 queue_t_unref(q, "Done with temporary pointer");
08327 }
08328 }
08329 ast_config_destroy(cfg);
08330 }
08331 }
08332
08333 ao2_lock(queues);
08334 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
08335 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
08336 float sl;
08337 struct call_queue *realtime_queue = NULL;
08338
08339 ao2_lock(q);
08340
08341
08342
08343
08344
08345 if (argc < 3 && q->realtime) {
08346 realtime_queue = find_load_queue_rt_friendly(q->name);
08347 if (!realtime_queue) {
08348 ao2_unlock(q);
08349 queue_t_unref(q, "Done with iterator");
08350 continue;
08351 }
08352 queue_t_unref(realtime_queue, "Queue is already in memory");
08353 }
08354
08355 if (argc == 3 && strcasecmp(q->name, argv[2])) {
08356 ao2_unlock(q);
08357 queue_t_unref(q, "Done with iterator");
08358 continue;
08359 }
08360 found = 1;
08361
08362 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
08363 if (q->maxlen) {
08364 ast_str_append(&out, 0, "%d", q->maxlen);
08365 } else {
08366 ast_str_append(&out, 0, "unlimited");
08367 }
08368 sl = 0;
08369 if (q->callscompleted > 0) {
08370 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
08371 }
08372 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
08373 int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
08374 q->callscompleted, q->callsabandoned,sl,q->servicelevel);
08375 do_print(s, fd, ast_str_buffer(out));
08376 if (!ao2_container_count(q->members)) {
08377 do_print(s, fd, " No Members");
08378 } else {
08379 struct member *mem;
08380
08381 do_print(s, fd, " Members: ");
08382 mem_iter = ao2_iterator_init(q->members, 0);
08383 while ((mem = ao2_iterator_next(&mem_iter))) {
08384 ast_str_set(&out, 0, " %s", mem->membername);
08385 if (strcasecmp(mem->membername, mem->interface)) {
08386 ast_str_append(&out, 0, " (%s", mem->interface);
08387 if (mem->state_interface) {
08388 ast_str_append(&out, 0, " from %s", mem->state_interface);
08389 }
08390 ast_str_append(&out, 0, ")");
08391 }
08392 if (mem->penalty) {
08393 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
08394 }
08395
08396 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
08397
08398 ast_str_append(&out, 0, "%s%s%s (%s)",
08399 mem->dynamic ? " (dynamic)" : "",
08400 mem->realtime ? " (realtime)" : "",
08401 mem->paused ? " (paused)" : "",
08402 ast_devstate2str(mem->status));
08403 if (mem->calls) {
08404 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
08405 mem->calls, (long) (time(NULL) - mem->lastcall));
08406 } else {
08407 ast_str_append(&out, 0, " has taken no calls yet");
08408 }
08409 do_print(s, fd, ast_str_buffer(out));
08410 ao2_ref(mem, -1);
08411 }
08412 ao2_iterator_destroy(&mem_iter);
08413 }
08414 if (!q->head) {
08415 do_print(s, fd, " No Callers");
08416 } else {
08417 struct queue_ent *qe;
08418 int pos = 1;
08419
08420 do_print(s, fd, " Callers: ");
08421 for (qe = q->head; qe; qe = qe->next) {
08422 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
08423 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
08424 (long) (now - qe->start) % 60, qe->prio);
08425 do_print(s, fd, ast_str_buffer(out));
08426 }
08427 }
08428 do_print(s, fd, "");
08429 ao2_unlock(q);
08430 queue_t_unref(q, "Done with iterator");
08431 }
08432 ao2_iterator_destroy(&queue_iter);
08433 ao2_unlock(queues);
08434 if (!found) {
08435 if (argc == 3) {
08436 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
08437 } else {
08438 ast_str_set(&out, 0, "No queues.");
08439 }
08440 do_print(s, fd, ast_str_buffer(out));
08441 }
08442 return CLI_SUCCESS;
08443 }
08444
08445
08446
08447
08448
08449
08450
08451
08452
08453
08454
08455
08456
08457
08458 static int word_in_list(const char *list, const char *word) {
08459 int list_len, word_len = strlen(word);
08460 const char *find, *end_find, *end_list;
08461
08462
08463 while(isspace(*list)) {
08464 list++;
08465 }
08466
08467 while((find = strstr(list, word))) {
08468
08469 if (find != list && *(find - 1) != ' ') {
08470 list = find;
08471
08472 while(!isspace(*list) && *list != '\0') {
08473 list++;
08474 }
08475
08476 while(isspace(*list)) {
08477 list++;
08478 }
08479 continue;
08480 }
08481
08482
08483 list_len = strlen(list);
08484 end_find = find + word_len;
08485 end_list = list + list_len;
08486 if (end_find == end_list || *end_find != ' ') {
08487 list = find;
08488
08489 while(!isspace(*list) && *list != '\0') {
08490 list++;
08491 }
08492
08493 while(isspace(*list)) {
08494 list++;
08495 }
08496 continue;
08497 }
08498
08499
08500 return 1;
08501 }
08502
08503 return 0;
08504 }
08505
08506
08507
08508
08509
08510
08511
08512
08513
08514
08515
08516
08517 static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
08518 {
08519 struct call_queue *q;
08520 char *ret = NULL;
08521 int which = 0;
08522 int wordlen = strlen(word);
08523 struct ao2_iterator queue_iter;
08524 const char *word_list = NULL;
08525
08526
08527
08528 if (word_list_offset && strlen(line) >= word_list_offset) {
08529 word_list = line + word_list_offset;
08530 }
08531
08532 queue_iter = ao2_iterator_init(queues, 0);
08533 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
08534 if (!strncasecmp(word, q->name, wordlen) && ++which > state
08535 && (!word_list_offset || !word_in_list(word_list, q->name))) {
08536 ret = ast_strdup(q->name);
08537 queue_t_unref(q, "Done with iterator");
08538 break;
08539 }
08540 queue_t_unref(q, "Done with iterator");
08541 }
08542 ao2_iterator_destroy(&queue_iter);
08543
08544
08545
08546
08547 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
08548 ret = ast_strdup("rules");
08549 }
08550
08551 return ret;
08552 }
08553
08554 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
08555 {
08556 if (pos == 2) {
08557 return complete_queue(line, word, pos, state, 0);
08558 }
08559 return NULL;
08560 }
08561
08562 static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08563 {
08564 switch ( cmd ) {
08565 case CLI_INIT:
08566 e->command = "queue show";
08567 e->usage =
08568 "Usage: queue show\n"
08569 " Provides summary information on a specified queue.\n";
08570 return NULL;
08571 case CLI_GENERATE:
08572 return complete_queue_show(a->line, a->word, a->pos, a->n);
08573 }
08574
08575 return __queues_show(NULL, a->fd, a->argc, a->argv);
08576 }
08577
08578
08579
08580
08581 static int manager_queues_show(struct mansession *s, const struct message *m)
08582 {
08583 static const char * const a[] = { "queue", "show" };
08584
08585 __queues_show(s, -1, 2, a);
08586 astman_append(s, "\r\n\r\n");
08587
08588 return RESULT_SUCCESS;
08589 }
08590
08591 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
08592 {
08593 const char *rule = astman_get_header(m, "Rule");
08594 const char *id = astman_get_header(m, "ActionID");
08595 struct rule_list *rl_iter;
08596 struct penalty_rule *pr_iter;
08597
08598 astman_append(s, "Response: Success\r\n");
08599 if (!ast_strlen_zero(id)) {
08600 astman_append(s, "ActionID: %s\r\n", id);
08601 }
08602
08603 AST_LIST_LOCK(&rule_lists);
08604 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
08605 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
08606 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
08607 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
08608 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 );
08609 }
08610 if (!ast_strlen_zero(rule)) {
08611 break;
08612 }
08613 }
08614 }
08615 AST_LIST_UNLOCK(&rule_lists);
08616
08617
08618
08619
08620
08621 astman_append(s, "\r\n\r\n");
08622
08623 return RESULT_SUCCESS;
08624 }
08625
08626
08627 static int manager_queues_summary(struct mansession *s, const struct message *m)
08628 {
08629 time_t now;
08630 int qmemcount = 0;
08631 int qmemavail = 0;
08632 int qchancount = 0;
08633 int qlongestholdtime = 0;
08634 const char *id = astman_get_header(m, "ActionID");
08635 const char *queuefilter = astman_get_header(m, "Queue");
08636 char idText[256] = "";
08637 struct call_queue *q;
08638 struct queue_ent *qe;
08639 struct member *mem;
08640 struct ao2_iterator queue_iter;
08641 struct ao2_iterator mem_iter;
08642
08643 astman_send_ack(s, m, "Queue summary will follow");
08644 time(&now);
08645 if (!ast_strlen_zero(id)) {
08646 snprintf(idText, 256, "ActionID: %s\r\n", id);
08647 }
08648 queue_iter = ao2_iterator_init(queues, 0);
08649 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
08650 ao2_lock(q);
08651
08652
08653 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
08654
08655 qmemcount = 0;
08656 qmemavail = 0;
08657 qchancount = 0;
08658 qlongestholdtime = 0;
08659
08660
08661 mem_iter = ao2_iterator_init(q->members, 0);
08662 while ((mem = ao2_iterator_next(&mem_iter))) {
08663 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
08664 ++qmemcount;
08665 if (member_status_available(mem->status) && !mem->paused) {
08666 ++qmemavail;
08667 }
08668 }
08669 ao2_ref(mem, -1);
08670 }
08671 ao2_iterator_destroy(&mem_iter);
08672 for (qe = q->head; qe; qe = qe->next) {
08673 if ((now - qe->start) > qlongestholdtime) {
08674 qlongestholdtime = now - qe->start;
08675 }
08676 ++qchancount;
08677 }
08678 astman_append(s, "Event: QueueSummary\r\n"
08679 "Queue: %s\r\n"
08680 "LoggedIn: %d\r\n"
08681 "Available: %d\r\n"
08682 "Callers: %d\r\n"
08683 "HoldTime: %d\r\n"
08684 "TalkTime: %d\r\n"
08685 "LongestHoldTime: %d\r\n"
08686 "%s"
08687 "\r\n",
08688 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
08689 }
08690 ao2_unlock(q);
08691 queue_t_unref(q, "Done with iterator");
08692 }
08693 ao2_iterator_destroy(&queue_iter);
08694 astman_append(s,
08695 "Event: QueueSummaryComplete\r\n"
08696 "%s"
08697 "\r\n", idText);
08698
08699 return RESULT_SUCCESS;
08700 }
08701
08702
08703 static int manager_queues_status(struct mansession *s, const struct message *m)
08704 {
08705 time_t now;
08706 int pos;
08707 const char *id = astman_get_header(m,"ActionID");
08708 const char *queuefilter = astman_get_header(m,"Queue");
08709 const char *memberfilter = astman_get_header(m,"Member");
08710 char idText[256] = "";
08711 struct call_queue *q;
08712 struct queue_ent *qe;
08713 float sl = 0;
08714 struct member *mem;
08715 struct ao2_iterator queue_iter;
08716 struct ao2_iterator mem_iter;
08717
08718 astman_send_ack(s, m, "Queue status will follow");
08719 time(&now);
08720 if (!ast_strlen_zero(id)) {
08721 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
08722 }
08723
08724 queue_iter = ao2_iterator_init(queues, 0);
08725 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
08726 ao2_lock(q);
08727
08728
08729 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
08730 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
08731 astman_append(s, "Event: QueueParams\r\n"
08732 "Queue: %s\r\n"
08733 "Max: %d\r\n"
08734 "Strategy: %s\r\n"
08735 "Calls: %d\r\n"
08736 "Holdtime: %d\r\n"
08737 "TalkTime: %d\r\n"
08738 "Completed: %d\r\n"
08739 "Abandoned: %d\r\n"
08740 "ServiceLevel: %d\r\n"
08741 "ServicelevelPerf: %2.1f\r\n"
08742 "Weight: %d\r\n"
08743 "%s"
08744 "\r\n",
08745 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
08746 q->callsabandoned, q->servicelevel, sl, q->weight, idText);
08747
08748 mem_iter = ao2_iterator_init(q->members, 0);
08749 while ((mem = ao2_iterator_next(&mem_iter))) {
08750 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
08751 astman_append(s, "Event: QueueMember\r\n"
08752 "Queue: %s\r\n"
08753 "Name: %s\r\n"
08754 "Location: %s\r\n"
08755 "StateInterface: %s\r\n"
08756 "Membership: %s\r\n"
08757 "Penalty: %d\r\n"
08758 "CallsTaken: %d\r\n"
08759 "LastCall: %d\r\n"
08760 "Status: %d\r\n"
08761 "Paused: %d\r\n"
08762 "%s"
08763 "\r\n",
08764 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
08765 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
08766 }
08767 ao2_ref(mem, -1);
08768 }
08769 ao2_iterator_destroy(&mem_iter);
08770
08771 pos = 1;
08772 for (qe = q->head; qe; qe = qe->next) {
08773 astman_append(s, "Event: QueueEntry\r\n"
08774 "Queue: %s\r\n"
08775 "Position: %d\r\n"
08776 "Channel: %s\r\n"
08777 "Uniqueid: %s\r\n"
08778 "CallerIDNum: %s\r\n"
08779 "CallerIDName: %s\r\n"
08780 "ConnectedLineNum: %s\r\n"
08781 "ConnectedLineName: %s\r\n"
08782 "Wait: %ld\r\n"
08783 "%s"
08784 "\r\n",
08785 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
08786 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
08787 S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
08788 S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
08789 S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
08790 (long) (now - qe->start), idText);
08791 }
08792 }
08793 ao2_unlock(q);
08794 queue_t_unref(q, "Done with iterator");
08795 }
08796 ao2_iterator_destroy(&queue_iter);
08797
08798 astman_append(s,
08799 "Event: QueueStatusComplete\r\n"
08800 "%s"
08801 "\r\n",idText);
08802
08803 return RESULT_SUCCESS;
08804 }
08805
08806 static int manager_add_queue_member(struct mansession *s, const struct message *m)
08807 {
08808 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
08809 int paused, penalty = 0;
08810
08811 queuename = astman_get_header(m, "Queue");
08812 interface = astman_get_header(m, "Interface");
08813 penalty_s = astman_get_header(m, "Penalty");
08814 paused_s = astman_get_header(m, "Paused");
08815 membername = astman_get_header(m, "MemberName");
08816 state_interface = astman_get_header(m, "StateInterface");
08817
08818 if (ast_strlen_zero(queuename)) {
08819 astman_send_error(s, m, "'Queue' not specified.");
08820 return 0;
08821 }
08822
08823 if (ast_strlen_zero(interface)) {
08824 astman_send_error(s, m, "'Interface' not specified.");
08825 return 0;
08826 }
08827
08828 if (ast_strlen_zero(penalty_s)) {
08829 penalty = 0;
08830 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
08831 penalty = 0;
08832 }
08833
08834 if (ast_strlen_zero(paused_s)) {
08835 paused = 0;
08836 } else {
08837 paused = abs(ast_true(paused_s));
08838 }
08839
08840 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
08841 case RES_OKAY:
08842 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
08843 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
08844 } else {
08845 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
08846 }
08847 astman_send_ack(s, m, "Added interface to queue");
08848 break;
08849 case RES_EXISTS:
08850 astman_send_error(s, m, "Unable to add interface: Already there");
08851 break;
08852 case RES_NOSUCHQUEUE:
08853 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
08854 break;
08855 case RES_OUTOFMEMORY:
08856 astman_send_error(s, m, "Out of memory");
08857 break;
08858 }
08859
08860 return 0;
08861 }
08862
08863 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
08864 {
08865 const char *queuename, *interface;
08866 struct member *mem = NULL;
08867
08868 queuename = astman_get_header(m, "Queue");
08869 interface = astman_get_header(m, "Interface");
08870
08871 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
08872 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
08873 return 0;
08874 }
08875
08876 if (log_membername_as_agent) {
08877 mem = find_member_by_queuename_and_interface(queuename, interface);
08878 }
08879
08880 switch (remove_from_queue(queuename, interface)) {
08881 case RES_OKAY:
08882 if (!mem || ast_strlen_zero(mem->membername)) {
08883 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
08884 } else {
08885 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
08886 }
08887 astman_send_ack(s, m, "Removed interface from queue");
08888 break;
08889 case RES_EXISTS:
08890 astman_send_error(s, m, "Unable to remove interface: Not there");
08891 break;
08892 case RES_NOSUCHQUEUE:
08893 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
08894 break;
08895 case RES_OUTOFMEMORY:
08896 astman_send_error(s, m, "Out of memory");
08897 break;
08898 case RES_NOT_DYNAMIC:
08899 astman_send_error(s, m, "Member not dynamic");
08900 break;
08901 }
08902
08903 if (mem) {
08904 ao2_ref(mem, -1);
08905 }
08906
08907 return 0;
08908 }
08909
08910 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
08911 {
08912 const char *queuename, *interface, *paused_s, *reason;
08913 int paused;
08914
08915 interface = astman_get_header(m, "Interface");
08916 paused_s = astman_get_header(m, "Paused");
08917 queuename = astman_get_header(m, "Queue");
08918 reason = astman_get_header(m, "Reason");
08919
08920 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
08921 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
08922 return 0;
08923 }
08924
08925 paused = abs(ast_true(paused_s));
08926
08927 if (set_member_paused(queuename, interface, reason, paused)) {
08928 astman_send_error(s, m, "Interface not found");
08929 } else {
08930 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
08931 }
08932 return 0;
08933 }
08934
08935 static int manager_queue_log_custom(struct mansession *s, const struct message *m)
08936 {
08937 const char *queuename, *event, *message, *interface, *uniqueid;
08938
08939 queuename = astman_get_header(m, "Queue");
08940 uniqueid = astman_get_header(m, "UniqueId");
08941 interface = astman_get_header(m, "Interface");
08942 event = astman_get_header(m, "Event");
08943 message = astman_get_header(m, "Message");
08944
08945 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
08946 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
08947 return 0;
08948 }
08949
08950 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
08951 astman_send_ack(s, m, "Event added successfully");
08952
08953 return 0;
08954 }
08955
08956 static int manager_queue_reload(struct mansession *s, const struct message *m)
08957 {
08958 struct ast_flags mask = {0,};
08959 const char *queuename = NULL;
08960 int header_found = 0;
08961
08962 queuename = astman_get_header(m, "Queue");
08963 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
08964 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
08965 header_found = 1;
08966 }
08967 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
08968 ast_set_flag(&mask, QUEUE_RELOAD_RULES);
08969 header_found = 1;
08970 }
08971 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
08972 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
08973 header_found = 1;
08974 }
08975
08976 if (!header_found) {
08977 ast_set_flag(&mask, AST_FLAGS_ALL);
08978 }
08979
08980 if (!reload_handler(1, &mask, queuename)) {
08981 astman_send_ack(s, m, "Queue reloaded successfully");
08982 } else {
08983 astman_send_error(s, m, "Error encountered while reloading queue");
08984 }
08985 return 0;
08986 }
08987
08988 static int manager_queue_reset(struct mansession *s, const struct message *m)
08989 {
08990 const char *queuename = NULL;
08991 struct ast_flags mask = {QUEUE_RESET_STATS,};
08992
08993 queuename = astman_get_header(m, "Queue");
08994
08995 if (!reload_handler(1, &mask, queuename)) {
08996 astman_send_ack(s, m, "Queue stats reset successfully");
08997 } else {
08998 astman_send_error(s, m, "Error encountered while resetting queue stats");
08999 }
09000 return 0;
09001 }
09002
09003 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
09004 {
09005
09006 switch (pos) {
09007 case 3:
09008 return NULL;
09009 case 4:
09010 return state == 0 ? ast_strdup("to") : NULL;
09011 case 5:
09012 return complete_queue(line, word, pos, state, 0);
09013 case 6:
09014 return state == 0 ? ast_strdup("penalty") : NULL;
09015 case 7:
09016 if (state < 100) {
09017 char *num;
09018 if ((num = ast_malloc(3))) {
09019 sprintf(num, "%d", state);
09020 }
09021 return num;
09022 } else {
09023 return NULL;
09024 }
09025 case 8:
09026 return state == 0 ? ast_strdup("as") : NULL;
09027 case 9:
09028 return NULL;
09029 default:
09030 return NULL;
09031 }
09032 }
09033
09034 static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
09035 {
09036 const char *queuename, *interface, *ringinuse_s;
09037 int ringinuse;
09038
09039 interface = astman_get_header(m, "Interface");
09040 ringinuse_s = astman_get_header(m, "RingInUse");
09041
09042
09043 queuename = astman_get_header(m, "Queue");
09044
09045 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
09046 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
09047 return 0;
09048 }
09049
09050 if (ast_true(ringinuse_s)) {
09051 ringinuse = 1;
09052 } else if (ast_false(ringinuse_s)) {
09053 ringinuse = 0;
09054 } else {
09055 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
09056 return 0;
09057 }
09058
09059 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
09060 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
09061 } else {
09062 astman_send_ack(s, m, "Interface ringinuse set successfully");
09063 }
09064
09065 return 0;
09066 }
09067
09068 static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
09069 {
09070 const char *queuename, *interface, *penalty_s;
09071 int penalty;
09072
09073 interface = astman_get_header(m, "Interface");
09074 penalty_s = astman_get_header(m, "Penalty");
09075
09076 queuename = astman_get_header(m, "Queue");
09077
09078 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
09079 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
09080 return 0;
09081 }
09082
09083 penalty = atoi(penalty_s);
09084
09085 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
09086 astman_send_error(s, m, "Invalid interface, queuename or penalty");
09087 } else {
09088 astman_send_ack(s, m, "Interface penalty set successfully");
09089 }
09090
09091 return 0;
09092 }
09093
09094 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09095 {
09096 const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
09097 int penalty;
09098
09099 switch ( cmd ) {
09100 case CLI_INIT:
09101 e->command = "queue add member";
09102 e->usage =
09103 "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
09104 " Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n";
09105 return NULL;
09106 case CLI_GENERATE:
09107 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
09108 }
09109
09110 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
09111 return CLI_SHOWUSAGE;
09112 } else if (strcmp(a->argv[4], "to")) {
09113 return CLI_SHOWUSAGE;
09114 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
09115 return CLI_SHOWUSAGE;
09116 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
09117 return CLI_SHOWUSAGE;
09118 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
09119 return CLI_SHOWUSAGE;
09120 }
09121
09122 queuename = a->argv[5];
09123 interface = a->argv[3];
09124 if (a->argc >= 8) {
09125 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
09126 if (penalty < 0) {
09127 ast_cli(a->fd, "Penalty must be >= 0\n");
09128 penalty = 0;
09129 }
09130 } else {
09131 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
09132 penalty = 0;
09133 }
09134 } else {
09135 penalty = 0;
09136 }
09137
09138 if (a->argc >= 10) {
09139 membername = a->argv[9];
09140 }
09141
09142 if (a->argc >= 12) {
09143 state_interface = a->argv[11];
09144 }
09145
09146 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
09147 case RES_OKAY:
09148 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
09149 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
09150 } else {
09151 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
09152 }
09153 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
09154 return CLI_SUCCESS;
09155 case RES_EXISTS:
09156 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
09157 return CLI_FAILURE;
09158 case RES_NOSUCHQUEUE:
09159 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
09160 return CLI_FAILURE;
09161 case RES_OUTOFMEMORY:
09162 ast_cli(a->fd, "Out of memory\n");
09163 return CLI_FAILURE;
09164 case RES_NOT_DYNAMIC:
09165 ast_cli(a->fd, "Member not dynamic\n");
09166 return CLI_FAILURE;
09167 default:
09168 return CLI_FAILURE;
09169 }
09170 }
09171
09172 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
09173 {
09174 int which = 0;
09175 struct call_queue *q;
09176 struct member *m;
09177 struct ao2_iterator queue_iter;
09178 struct ao2_iterator mem_iter;
09179 int wordlen = strlen(word);
09180
09181
09182 if (pos > 5 || pos < 3) {
09183 return NULL;
09184 }
09185 if (pos == 4) {
09186 return (state == 0 ? ast_strdup("from") : NULL);
09187 }
09188
09189 if (pos == 5) {
09190 return complete_queue(line, word, pos, state, 0);
09191 }
09192
09193
09194 queue_iter = ao2_iterator_init(queues, 0);
09195 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
09196 ao2_lock(q);
09197 mem_iter = ao2_iterator_init(q->members, 0);
09198 while ((m = ao2_iterator_next(&mem_iter))) {
09199 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
09200 char *tmp;
09201 tmp = ast_strdup(m->interface);
09202 ao2_ref(m, -1);
09203 ao2_iterator_destroy(&mem_iter);
09204 ao2_unlock(q);
09205 queue_t_unref(q, "Done with iterator, returning interface name");
09206 ao2_iterator_destroy(&queue_iter);
09207 return tmp;
09208 }
09209 ao2_ref(m, -1);
09210 }
09211 ao2_iterator_destroy(&mem_iter);
09212 ao2_unlock(q);
09213 queue_t_unref(q, "Done with iterator");
09214 }
09215 ao2_iterator_destroy(&queue_iter);
09216
09217 return NULL;
09218 }
09219
09220 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09221 {
09222 const char *queuename, *interface;
09223 struct member *mem = NULL;
09224 char *res = CLI_FAILURE;
09225
09226 switch (cmd) {
09227 case CLI_INIT:
09228 e->command = "queue remove member";
09229 e->usage =
09230 "Usage: queue remove member <channel> from <queue>\n"
09231 " Remove a specific channel from a queue.\n";
09232 return NULL;
09233 case CLI_GENERATE:
09234 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
09235 }
09236
09237 if (a->argc != 6) {
09238 return CLI_SHOWUSAGE;
09239 } else if (strcmp(a->argv[4], "from")) {
09240 return CLI_SHOWUSAGE;
09241 }
09242
09243 queuename = a->argv[5];
09244 interface = a->argv[3];
09245
09246 if (log_membername_as_agent) {
09247 mem = find_member_by_queuename_and_interface(queuename, interface);
09248 }
09249
09250 switch (remove_from_queue(queuename, interface)) {
09251 case RES_OKAY:
09252 if (!mem || ast_strlen_zero(mem->membername)) {
09253 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
09254 } else {
09255 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
09256 }
09257 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
09258 res = CLI_SUCCESS;
09259 break;
09260 case RES_EXISTS:
09261 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
09262 break;
09263 case RES_NOSUCHQUEUE:
09264 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
09265 break;
09266 case RES_OUTOFMEMORY:
09267 ast_cli(a->fd, "Out of memory\n");
09268 break;
09269 case RES_NOT_DYNAMIC:
09270 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
09271 break;
09272 }
09273
09274 if (mem) {
09275 ao2_ref(mem, -1);
09276 }
09277
09278 return res;
09279 }
09280
09281 static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
09282 {
09283
09284 switch (pos) {
09285 case 3:
09286 return NULL;
09287 case 4:
09288 return state == 0 ? ast_strdup("queue") : NULL;
09289 case 5:
09290 return complete_queue(line, word, pos, state, 0);
09291 case 6:
09292 return state == 0 ? ast_strdup("reason") : NULL;
09293 case 7:
09294 return NULL;
09295 default:
09296 return NULL;
09297 }
09298 }
09299
09300 static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09301 {
09302 const char *queuename, *interface, *reason;
09303 int paused;
09304
09305 switch (cmd) {
09306 case CLI_INIT:
09307 e->command = "queue {pause|unpause} member";
09308 e->usage =
09309 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
09310 " Pause or unpause a queue member. Not specifying a particular queue\n"
09311 " will pause or unpause a member across all queues to which the member\n"
09312 " belongs.\n";
09313 return NULL;
09314 case CLI_GENERATE:
09315 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
09316 }
09317
09318 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
09319 return CLI_SHOWUSAGE;
09320 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
09321 return CLI_SHOWUSAGE;
09322 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
09323 return CLI_SHOWUSAGE;
09324 }
09325
09326
09327 interface = a->argv[3];
09328 queuename = a->argc >= 6 ? a->argv[5] : NULL;
09329 reason = a->argc == 8 ? a->argv[7] : NULL;
09330 paused = !strcasecmp(a->argv[1], "pause");
09331
09332 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
09333 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
09334 if (!ast_strlen_zero(queuename)) {
09335 ast_cli(a->fd, " in queue '%s'", queuename);
09336 }
09337 if (!ast_strlen_zero(reason)) {
09338 ast_cli(a->fd, " for reason '%s'", reason);
09339 }
09340 ast_cli(a->fd, "\n");
09341 return CLI_SUCCESS;
09342 } else {
09343 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
09344 if (!ast_strlen_zero(queuename)) {
09345 ast_cli(a->fd, " in queue '%s'", queuename);
09346 }
09347 if (!ast_strlen_zero(reason)) {
09348 ast_cli(a->fd, " for reason '%s'", reason);
09349 }
09350 ast_cli(a->fd, "\n");
09351 return CLI_FAILURE;
09352 }
09353 }
09354
09355 static char *complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
09356 {
09357
09358 switch (pos) {
09359 case 4:
09360 if (state == 0) {
09361 return ast_strdup("on");
09362 } else {
09363 return NULL;
09364 }
09365 case 6:
09366 if (state == 0) {
09367 return ast_strdup("in");
09368 } else {
09369 return NULL;
09370 }
09371 case 7:
09372 return complete_queue(line, word, pos, state, 0);
09373 default:
09374 return NULL;
09375 }
09376 }
09377
09378 static char *handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09379 {
09380 const char *queuename = NULL, *interface;
09381 int ringinuse;
09382
09383 switch (cmd) {
09384 case CLI_INIT:
09385 e->command = "queue set ringinuse";
09386 e->usage =
09387 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
09388 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
09389 " then that interface's penalty is set in all queues to which that interface is a member.\n";
09390 break;
09391 return NULL;
09392 case CLI_GENERATE:
09393 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
09394 }
09395
09396
09397 if (a->argc != 6 && a->argc != 8) {
09398 return CLI_SHOWUSAGE;
09399 }
09400
09401
09402 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
09403 return CLI_SHOWUSAGE;
09404 }
09405
09406
09407 if (a->argc == 8) {
09408 queuename = a->argv[7];
09409 }
09410
09411
09412 interface = a->argv[5];
09413
09414
09415 if (ast_true(a->argv[3])) {
09416 ringinuse = 1;
09417 } else if (ast_false(a->argv[3])) {
09418 ringinuse = 0;
09419 } else {
09420 return CLI_SHOWUSAGE;
09421 }
09422
09423 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
09424 case RESULT_SUCCESS:
09425 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
09426 return CLI_SUCCESS;
09427 case RESULT_FAILURE:
09428 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
09429 return CLI_FAILURE;
09430 default:
09431 return CLI_FAILURE;
09432 }
09433 }
09434
09435 static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09436 {
09437 const char *queuename = NULL, *interface;
09438 int penalty = 0;
09439
09440 switch (cmd) {
09441 case CLI_INIT:
09442 e->command = "queue set penalty";
09443 e->usage =
09444 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
09445 " Set a member's penalty in the queue specified. If no queue is specified\n"
09446 " then that interface's penalty is set in all queues to which that interface is a member\n";
09447 return NULL;
09448 case CLI_GENERATE:
09449 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
09450 }
09451
09452 if (a->argc != 6 && a->argc != 8) {
09453 return CLI_SHOWUSAGE;
09454 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
09455 return CLI_SHOWUSAGE;
09456 }
09457
09458 if (a->argc == 8) {
09459 queuename = a->argv[7];
09460 }
09461 interface = a->argv[5];
09462 penalty = atoi(a->argv[3]);
09463
09464 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
09465 case RESULT_SUCCESS:
09466 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
09467 return CLI_SUCCESS;
09468 case RESULT_FAILURE:
09469 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
09470 return CLI_FAILURE;
09471 default:
09472 return CLI_FAILURE;
09473 }
09474 }
09475
09476 static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
09477 {
09478 int which = 0;
09479 struct rule_list *rl_iter;
09480 int wordlen = strlen(word);
09481 char *ret = NULL;
09482 if (pos != 3) {
09483 return NULL;
09484 }
09485
09486 AST_LIST_LOCK(&rule_lists);
09487 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
09488 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
09489 ret = ast_strdup(rl_iter->name);
09490 break;
09491 }
09492 }
09493 AST_LIST_UNLOCK(&rule_lists);
09494
09495 return ret;
09496 }
09497
09498 static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09499 {
09500 const char *rule;
09501 struct rule_list *rl_iter;
09502 struct penalty_rule *pr_iter;
09503 switch (cmd) {
09504 case CLI_INIT:
09505 e->command = "queue show rules";
09506 e->usage =
09507 "Usage: queue show rules [rulename]\n"
09508 " Show the list of rules associated with rulename. If no\n"
09509 " rulename is specified, list all rules defined in queuerules.conf\n";
09510 return NULL;
09511 case CLI_GENERATE:
09512 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
09513 }
09514
09515 if (a->argc != 3 && a->argc != 4) {
09516 return CLI_SHOWUSAGE;
09517 }
09518
09519 rule = a->argc == 4 ? a->argv[3] : "";
09520 AST_LIST_LOCK(&rule_lists);
09521 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
09522 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
09523 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
09524 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
09525 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);
09526 }
09527 }
09528 }
09529 AST_LIST_UNLOCK(&rule_lists);
09530 return CLI_SUCCESS;
09531 }
09532
09533 static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09534 {
09535 struct ast_flags mask = {QUEUE_RESET_STATS,};
09536 int i;
09537
09538 switch (cmd) {
09539 case CLI_INIT:
09540 e->command = "queue reset stats";
09541 e->usage =
09542 "Usage: queue reset stats [<queuenames>]\n"
09543 "\n"
09544 "Issuing this command will reset statistics for\n"
09545 "<queuenames>, or for all queues if no queue is\n"
09546 "specified.\n";
09547 return NULL;
09548 case CLI_GENERATE:
09549 if (a->pos >= 3) {
09550 return complete_queue(a->line, a->word, a->pos, a->n, 17);
09551 } else {
09552 return NULL;
09553 }
09554 }
09555
09556 if (a->argc < 3) {
09557 return CLI_SHOWUSAGE;
09558 }
09559
09560 if (a->argc == 3) {
09561 reload_handler(1, &mask, NULL);
09562 return CLI_SUCCESS;
09563 }
09564
09565 for (i = 3; i < a->argc; ++i) {
09566 reload_handler(1, &mask, a->argv[i]);
09567 }
09568
09569 return CLI_SUCCESS;
09570 }
09571
09572 static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
09573 {
09574 struct ast_flags mask = {0,};
09575 int i;
09576
09577 switch (cmd) {
09578 case CLI_INIT:
09579 e->command = "queue reload {parameters|members|rules|all}";
09580 e->usage =
09581 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
09582 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
09583 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
09584 "specified in order to know what information to reload. Below is an explanation\n"
09585 "of each of these qualifiers.\n"
09586 "\n"
09587 "\t'members' - reload queue members from queues.conf\n"
09588 "\t'parameters' - reload all queue options except for queue members\n"
09589 "\t'rules' - reload the queuerules.conf file\n"
09590 "\t'all' - reload queue rules, parameters, and members\n"
09591 "\n"
09592 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
09593 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
09594 "one queue is specified when using this command, reloading queue rules may cause\n"
09595 "other queues to be affected\n";
09596 return NULL;
09597 case CLI_GENERATE:
09598 if (a->pos >= 3) {
09599
09600 const char *command_end = a->line + strlen("queue reload ");
09601 command_end = strchr(command_end, ' ');
09602 if (!command_end) {
09603 command_end = a->line + strlen(a->line);
09604 }
09605 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
09606 } else {
09607 return NULL;
09608 }
09609 }
09610
09611 if (a->argc < 3)
09612 return CLI_SHOWUSAGE;
09613
09614 if (!strcasecmp(a->argv[2], "rules")) {
09615 ast_set_flag(&mask, QUEUE_RELOAD_RULES);
09616 } else if (!strcasecmp(a->argv[2], "members")) {
09617 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
09618 } else if (!strcasecmp(a->argv[2], "parameters")) {
09619 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
09620 } else if (!strcasecmp(a->argv[2], "all")) {
09621 ast_set_flag(&mask, AST_FLAGS_ALL);
09622 }
09623
09624 if (a->argc == 3) {
09625 reload_handler(1, &mask, NULL);
09626 return CLI_SUCCESS;
09627 }
09628
09629 for (i = 3; i < a->argc; ++i) {
09630 reload_handler(1, &mask, a->argv[i]);
09631 }
09632
09633 return CLI_SUCCESS;
09634 }
09635
09636 static const char qpm_cmd_usage[] =
09637 "Usage: queue pause member <channel> in <queue> reason <reason>\n";
09638
09639 static const char qum_cmd_usage[] =
09640 "Usage: queue unpause member <channel> in <queue> reason <reason>\n";
09641
09642 static const char qsmp_cmd_usage[] =
09643 "Usage: queue set member penalty <channel> from <queue> <penalty>\n";
09644
09645 static struct ast_cli_entry cli_queue[] = {
09646 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
09647 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
09648 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
09649 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
09650 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
09651 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
09652 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
09653 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
09654 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
09655 };
09656
09657
09658 #define DATA_EXPORT_CALL_QUEUE(MEMBER) \
09659 MEMBER(call_queue, name, AST_DATA_STRING) \
09660 MEMBER(call_queue, moh, AST_DATA_STRING) \
09661 MEMBER(call_queue, announce, AST_DATA_STRING) \
09662 MEMBER(call_queue, context, AST_DATA_STRING) \
09663 MEMBER(call_queue, membermacro, AST_DATA_STRING) \
09664 MEMBER(call_queue, membergosub, AST_DATA_STRING) \
09665 MEMBER(call_queue, defaultrule, AST_DATA_STRING) \
09666 MEMBER(call_queue, sound_next, AST_DATA_STRING) \
09667 MEMBER(call_queue, sound_thereare, AST_DATA_STRING) \
09668 MEMBER(call_queue, sound_calls, AST_DATA_STRING) \
09669 MEMBER(call_queue, queue_quantity1, AST_DATA_STRING) \
09670 MEMBER(call_queue, queue_quantity2, AST_DATA_STRING) \
09671 MEMBER(call_queue, sound_holdtime, AST_DATA_STRING) \
09672 MEMBER(call_queue, sound_minutes, AST_DATA_STRING) \
09673 MEMBER(call_queue, sound_minute, AST_DATA_STRING) \
09674 MEMBER(call_queue, sound_seconds, AST_DATA_STRING) \
09675 MEMBER(call_queue, sound_thanks, AST_DATA_STRING) \
09676 MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING) \
09677 MEMBER(call_queue, sound_reporthold, AST_DATA_STRING) \
09678 MEMBER(call_queue, dead, AST_DATA_BOOLEAN) \
09679 MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN) \
09680 MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN) \
09681 MEMBER(call_queue, announce_to_first_user, AST_DATA_BOOLEAN) \
09682 MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN) \
09683 MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN) \
09684 MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN) \
09685 MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN) \
09686 MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN) \
09687 MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN) \
09688 MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER) \
09689 MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN) \
09690 MEMBER(call_queue, realtime, AST_DATA_BOOLEAN) \
09691 MEMBER(call_queue, found, AST_DATA_BOOLEAN) \
09692 MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \
09693 MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS) \
09694 MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS) \
09695 MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS) \
09696 MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER) \
09697 MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER) \
09698 MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS) \
09699 MEMBER(call_queue, holdtime, AST_DATA_SECONDS) \
09700 MEMBER(call_queue, talktime, AST_DATA_SECONDS) \
09701 MEMBER(call_queue, callscompleted, AST_DATA_INTEGER) \
09702 MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER) \
09703 MEMBER(call_queue, servicelevel, AST_DATA_INTEGER) \
09704 MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \
09705 MEMBER(call_queue, monfmt, AST_DATA_STRING) \
09706 MEMBER(call_queue, montype, AST_DATA_INTEGER) \
09707 MEMBER(call_queue, count, AST_DATA_INTEGER) \
09708 MEMBER(call_queue, maxlen, AST_DATA_INTEGER) \
09709 MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS) \
09710 MEMBER(call_queue, retry, AST_DATA_SECONDS) \
09711 MEMBER(call_queue, timeout, AST_DATA_SECONDS) \
09712 MEMBER(call_queue, weight, AST_DATA_INTEGER) \
09713 MEMBER(call_queue, autopause, AST_DATA_INTEGER) \
09714 MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER) \
09715 MEMBER(call_queue, rrpos, AST_DATA_INTEGER) \
09716 MEMBER(call_queue, memberdelay, AST_DATA_INTEGER) \
09717 MEMBER(call_queue, autofill, AST_DATA_INTEGER) \
09718 MEMBER(call_queue, members, AST_DATA_CONTAINER)
09719
09720 AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE);
09721
09722
09723 #define DATA_EXPORT_MEMBER(MEMBER) \
09724 MEMBER(member, interface, AST_DATA_STRING) \
09725 MEMBER(member, state_interface, AST_DATA_STRING) \
09726 MEMBER(member, membername, AST_DATA_STRING) \
09727 MEMBER(member, penalty, AST_DATA_INTEGER) \
09728 MEMBER(member, calls, AST_DATA_INTEGER) \
09729 MEMBER(member, dynamic, AST_DATA_INTEGER) \
09730 MEMBER(member, realtime, AST_DATA_INTEGER) \
09731 MEMBER(member, status, AST_DATA_INTEGER) \
09732 MEMBER(member, paused, AST_DATA_BOOLEAN) \
09733 MEMBER(member, rt_uniqueid, AST_DATA_STRING)
09734
09735 AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER);
09736
09737 #define DATA_EXPORT_QUEUE_ENT(MEMBER) \
09738 MEMBER(queue_ent, moh, AST_DATA_STRING) \
09739 MEMBER(queue_ent, announce, AST_DATA_STRING) \
09740 MEMBER(queue_ent, context, AST_DATA_STRING) \
09741 MEMBER(queue_ent, digits, AST_DATA_STRING) \
09742 MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER) \
09743 MEMBER(queue_ent, pos, AST_DATA_INTEGER) \
09744 MEMBER(queue_ent, prio, AST_DATA_INTEGER) \
09745 MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER) \
09746 MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER) \
09747 MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \
09748 MEMBER(queue_ent, last_pos, AST_DATA_INTEGER) \
09749 MEMBER(queue_ent, opos, AST_DATA_INTEGER) \
09750 MEMBER(queue_ent, handled, AST_DATA_INTEGER) \
09751 MEMBER(queue_ent, pending, AST_DATA_INTEGER) \
09752 MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER) \
09753 MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER) \
09754 MEMBER(queue_ent, linpos, AST_DATA_INTEGER) \
09755 MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER) \
09756 MEMBER(queue_ent, start, AST_DATA_INTEGER) \
09757 MEMBER(queue_ent, expire, AST_DATA_INTEGER) \
09758 MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER)
09759
09760 AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT);
09761
09762
09763
09764
09765
09766
09767
09768
09769 static void queues_data_provider_get_helper(const struct ast_data_search *search,
09770 struct ast_data *data_root, struct call_queue *queue)
09771 {
09772 struct ao2_iterator im;
09773 struct member *member;
09774 struct queue_ent *qe;
09775 struct ast_data *data_queue, *data_members = NULL, *enum_node;
09776 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
09777
09778 data_queue = ast_data_add_node(data_root, "queue");
09779 if (!data_queue) {
09780 return;
09781 }
09782
09783 ast_data_add_structure(call_queue, data_queue, queue);
09784
09785 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
09786 ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
09787
09788
09789 enum_node = ast_data_add_node(data_queue, "announceposition");
09790 if (!enum_node) {
09791 return;
09792 }
09793 switch (queue->announceposition) {
09794 case ANNOUNCEPOSITION_LIMIT:
09795 ast_data_add_str(enum_node, "text", "limit");
09796 break;
09797 case ANNOUNCEPOSITION_MORE_THAN:
09798 ast_data_add_str(enum_node, "text", "more");
09799 break;
09800 case ANNOUNCEPOSITION_YES:
09801 ast_data_add_str(enum_node, "text", "yes");
09802 break;
09803 case ANNOUNCEPOSITION_NO:
09804 ast_data_add_str(enum_node, "text", "no");
09805 break;
09806 default:
09807 ast_data_add_str(enum_node, "text", "unknown");
09808 break;
09809 }
09810 ast_data_add_int(enum_node, "value", queue->announceposition);
09811
09812
09813 im = ao2_iterator_init(queue->members, 0);
09814 while ((member = ao2_iterator_next(&im))) {
09815 if (!data_members) {
09816 data_members = ast_data_add_node(data_queue, "members");
09817 if (!data_members) {
09818 ao2_ref(member, -1);
09819 continue;
09820 }
09821 }
09822
09823 data_member = ast_data_add_node(data_members, "member");
09824 if (!data_member) {
09825 ao2_ref(member, -1);
09826 continue;
09827 }
09828
09829 ast_data_add_structure(member, data_member, member);
09830
09831 ao2_ref(member, -1);
09832 }
09833 ao2_iterator_destroy(&im);
09834
09835
09836 if (queue->head) {
09837 for (qe = queue->head; qe; qe = qe->next) {
09838 if (!data_callers) {
09839 data_callers = ast_data_add_node(data_queue, "callers");
09840 if (!data_callers) {
09841 continue;
09842 }
09843 }
09844
09845 data_caller = ast_data_add_node(data_callers, "caller");
09846 if (!data_caller) {
09847 continue;
09848 }
09849
09850 ast_data_add_structure(queue_ent, data_caller, qe);
09851
09852
09853 data_caller_channel = ast_data_add_node(data_caller, "channel");
09854 if (!data_caller_channel) {
09855 continue;
09856 }
09857
09858 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
09859 }
09860 }
09861
09862
09863 if (!ast_data_search_match(search, data_queue)) {
09864 ast_data_remove_node(data_root, data_queue);
09865 }
09866 }
09867
09868
09869
09870
09871
09872
09873
09874
09875 static int queues_data_provider_get(const struct ast_data_search *search,
09876 struct ast_data *data_root)
09877 {
09878 struct ao2_iterator i;
09879 struct call_queue *queue, *queue_realtime = NULL;
09880 struct ast_config *cfg;
09881 char *queuename;
09882
09883
09884 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
09885 if (cfg) {
09886 for (queuename = ast_category_browse(cfg, NULL);
09887 !ast_strlen_zero(queuename);
09888 queuename = ast_category_browse(cfg, queuename)) {
09889 if ((queue = find_load_queue_rt_friendly(queuename))) {
09890 queue_unref(queue);
09891 }
09892 }
09893 ast_config_destroy(cfg);
09894 }
09895
09896
09897 i = ao2_iterator_init(queues, 0);
09898 while ((queue = ao2_iterator_next(&i))) {
09899 ao2_lock(queue);
09900 if (queue->realtime) {
09901 queue_realtime = find_load_queue_rt_friendly(queue->name);
09902 if (!queue_realtime) {
09903 ao2_unlock(queue);
09904 queue_unref(queue);
09905 continue;
09906 }
09907 queue_unref(queue_realtime);
09908 }
09909
09910 queues_data_provider_get_helper(search, data_root, queue);
09911 ao2_unlock(queue);
09912 queue_unref(queue);
09913 }
09914 ao2_iterator_destroy(&i);
09915
09916 return 0;
09917 }
09918
09919 static const struct ast_data_handler queues_data_provider = {
09920 .version = AST_DATA_HANDLER_VERSION,
09921 .get = queues_data_provider_get
09922 };
09923
09924 static const struct ast_data_entry queue_data_providers[] = {
09925 AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
09926 };
09927
09928 static int unload_module(void)
09929 {
09930 int res;
09931 struct ao2_iterator q_iter;
09932 struct call_queue *q = NULL;
09933
09934 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
09935 res = ast_manager_unregister("QueueStatus");
09936 res |= ast_manager_unregister("Queues");
09937 res |= ast_manager_unregister("QueueRule");
09938 res |= ast_manager_unregister("QueueSummary");
09939 res |= ast_manager_unregister("QueueAdd");
09940 res |= ast_manager_unregister("QueueRemove");
09941 res |= ast_manager_unregister("QueuePause");
09942 res |= ast_manager_unregister("QueueLog");
09943 res |= ast_manager_unregister("QueuePenalty");
09944 res |= ast_manager_unregister("QueueReload");
09945 res |= ast_manager_unregister("QueueReset");
09946 res |= ast_manager_unregister("QueueMemberRingInUse");
09947 res |= ast_unregister_application(app_aqm);
09948 res |= ast_unregister_application(app_rqm);
09949 res |= ast_unregister_application(app_pqm);
09950 res |= ast_unregister_application(app_upqm);
09951 res |= ast_unregister_application(app_ql);
09952 res |= ast_unregister_application(app);
09953 res |= ast_custom_function_unregister(&queueexists_function);
09954 res |= ast_custom_function_unregister(&queuevar_function);
09955 res |= ast_custom_function_unregister(&queuemembercount_function);
09956 res |= ast_custom_function_unregister(&queuemembercount_dep);
09957 res |= ast_custom_function_unregister(&queuememberlist_function);
09958 res |= ast_custom_function_unregister(&queuewaitingcount_function);
09959 res |= ast_custom_function_unregister(&queuememberpenalty_function);
09960
09961 res |= ast_data_unregister(NULL);
09962
09963 if (device_state_sub)
09964 ast_event_unsubscribe(device_state_sub);
09965
09966 ast_extension_state_del(0, extension_state_cb);
09967
09968 q_iter = ao2_iterator_init(queues, 0);
09969 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
09970 queues_t_unlink(queues, q, "Remove queue from container due to unload");
09971 queue_t_unref(q, "Done with iterator");
09972 }
09973 ao2_iterator_destroy(&q_iter);
09974 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
09975 ao2_ref(queues, -1);
09976 ast_unload_realtime("queue_members");
09977 return res;
09978 }
09979
09980 static int load_module(void)
09981 {
09982 int res;
09983 struct ast_flags mask = {AST_FLAGS_ALL, };
09984 struct ast_config *member_config;
09985
09986 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
09987
09988 use_weight = 0;
09989
09990 if (reload_handler(0, &mask, NULL))
09991 return AST_MODULE_LOAD_DECLINE;
09992
09993 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
09994
09995
09996
09997
09998
09999 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
10000 if (!member_config) {
10001 realtime_ringinuse_field = "ringinuse";
10002 } else {
10003 const char *config_val;
10004 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
10005 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
10006 realtime_ringinuse_field = "ringinuse";
10007 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
10008 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
10009 realtime_ringinuse_field = "ignorebusy";
10010 } else {
10011 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
10012 realtime_ringinuse_field = "ringinuse";
10013 }
10014 }
10015
10016 ast_config_destroy(member_config);
10017
10018 if (queue_persistent_members)
10019 reload_queue_members();
10020
10021 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
10022
10023 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
10024 res = ast_register_application_xml(app, queue_exec);
10025 res |= ast_register_application_xml(app_aqm, aqm_exec);
10026 res |= ast_register_application_xml(app_rqm, rqm_exec);
10027 res |= ast_register_application_xml(app_pqm, pqm_exec);
10028 res |= ast_register_application_xml(app_upqm, upqm_exec);
10029 res |= ast_register_application_xml(app_ql, ql_exec);
10030 res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
10031 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
10032 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
10033 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
10034 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
10035 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
10036 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
10037 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
10038 res |= ast_manager_register_xml("QueueMemberRingInUse", EVENT_FLAG_AGENT, manager_queue_member_ringinuse);
10039 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
10040 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
10041 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
10042 res |= ast_custom_function_register(&queuevar_function);
10043 res |= ast_custom_function_register(&queueexists_function);
10044 res |= ast_custom_function_register(&queuemembercount_function);
10045 res |= ast_custom_function_register(&queuemembercount_dep);
10046 res |= ast_custom_function_register(&queuememberlist_function);
10047 res |= ast_custom_function_register(&queuewaitingcount_function);
10048 res |= ast_custom_function_register(&queuememberpenalty_function);
10049
10050 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
10051 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
10052 }
10053
10054
10055 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
10056 res = -1;
10057 }
10058
10059 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
10060
10061 return res ? AST_MODULE_LOAD_DECLINE : 0;
10062 }
10063
10064 static int reload(void)
10065 {
10066 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
10067 ast_unload_realtime("queue_members");
10068 reload_handler(1, &mask, NULL);
10069 return 0;
10070 }
10071
10072
10073
10074
10075 static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface)
10076 {
10077 struct member *mem = NULL;
10078 struct call_queue *q;
10079
10080 if ((q = find_load_queue_rt_friendly(queuename))) {
10081 ao2_lock(q);
10082 mem = ao2_find(q->members, interface, OBJ_KEY);
10083 ao2_unlock(q);
10084 queue_t_unref(q, "Expiring temporary reference.");
10085 }
10086 return mem;
10087 }
10088
10089 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
10090 .load = load_module,
10091 .unload = unload_module,
10092 .reload = reload,
10093 .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
10094 .nonoptreq = "res_monitor",
10095 );
10096