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