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