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