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