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