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