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 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 420146 $")
00033
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"
00036 #include <ctype.h>
00037 #include <time.h>
00038 #include <sys/time.h>
00039 #if defined(HAVE_SYSINFO)
00040 #include <sys/sysinfo.h>
00041 #endif
00042 #if defined(SOLARIS)
00043 #include <sys/loadavg.h>
00044 #endif
00045
00046 #include "asterisk/lock.h"
00047 #include "asterisk/cli.h"
00048 #include "asterisk/pbx.h"
00049 #include "asterisk/channel.h"
00050 #include "asterisk/file.h"
00051 #include "asterisk/callerid.h"
00052 #include "asterisk/cdr.h"
00053 #include "asterisk/cel.h"
00054 #include "asterisk/config.h"
00055 #include "asterisk/term.h"
00056 #include "asterisk/time.h"
00057 #include "asterisk/manager.h"
00058 #include "asterisk/ast_expr.h"
00059 #include "asterisk/linkedlists.h"
00060 #define SAY_STUBS
00061 #include "asterisk/say.h"
00062 #include "asterisk/utils.h"
00063 #include "asterisk/causes.h"
00064 #include "asterisk/musiconhold.h"
00065 #include "asterisk/app.h"
00066 #include "asterisk/devicestate.h"
00067 #include "asterisk/event.h"
00068 #include "asterisk/hashtab.h"
00069 #include "asterisk/module.h"
00070 #include "asterisk/indications.h"
00071 #include "asterisk/taskprocessor.h"
00072 #include "asterisk/xmldoc.h"
00073 #include "asterisk/astobj2.h"
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
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 #ifdef LOW_MEMORY
00826 #define EXT_DATA_SIZE 256
00827 #else
00828 #define EXT_DATA_SIZE 8192
00829 #endif
00830
00831 #define SWITCH_DATA_LENGTH 256
00832
00833 #define VAR_BUF_SIZE 4096
00834
00835 #define VAR_NORMAL 1
00836 #define VAR_SOFTTRAN 2
00837 #define VAR_HARDTRAN 3
00838
00839 #define BACKGROUND_SKIP (1 << 0)
00840 #define BACKGROUND_NOANSWER (1 << 1)
00841 #define BACKGROUND_MATCHEXTEN (1 << 2)
00842 #define BACKGROUND_PLAYBACK (1 << 3)
00843
00844 AST_APP_OPTIONS(background_opts, {
00845 AST_APP_OPTION('s', BACKGROUND_SKIP),
00846 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
00847 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
00848 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
00849 });
00850
00851 #define WAITEXTEN_MOH (1 << 0)
00852 #define WAITEXTEN_DIALTONE (1 << 1)
00853
00854 AST_APP_OPTIONS(waitexten_opts, {
00855 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
00856 AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
00857 });
00858
00859 struct ast_context;
00860 struct ast_app;
00861
00862 static struct ast_taskprocessor *device_state_tps;
00863
00864 AST_THREADSTORAGE(switch_data);
00865 AST_THREADSTORAGE(extensionstate_buf);
00866
00867
00868
00869
00870 AST_THREADSTORAGE(thread_inhibit_escalations_tl);
00871
00872
00873
00874
00875
00876 static int live_dangerously;
00877
00878
00879
00880
00881
00882
00883
00884 struct ast_exten {
00885 char *exten;
00886 int matchcid;
00887 const char *cidmatch;
00888 int priority;
00889 const char *label;
00890 struct ast_context *parent;
00891 const char *app;
00892 struct ast_app *cached_app;
00893 void *data;
00894 void (*datad)(void *);
00895 struct ast_exten *peer;
00896 struct ast_hashtab *peer_table;
00897 struct ast_hashtab *peer_label_table;
00898 const char *registrar;
00899 struct ast_exten *next;
00900 char stuff[0];
00901 };
00902
00903
00904 struct ast_include {
00905 const char *name;
00906 const char *rname;
00907 const char *registrar;
00908 int hastime;
00909 struct ast_timing timing;
00910 struct ast_include *next;
00911 char stuff[0];
00912 };
00913
00914
00915 struct ast_sw {
00916 char *name;
00917 const char *registrar;
00918 char *data;
00919 int eval;
00920 AST_LIST_ENTRY(ast_sw) list;
00921 char stuff[0];
00922 };
00923
00924
00925 struct ast_ignorepat {
00926 const char *registrar;
00927 struct ast_ignorepat *next;
00928 const char pattern[0];
00929 };
00930
00931
00932 struct match_char
00933 {
00934 int is_pattern;
00935 int deleted;
00936 int specificity;
00937 struct match_char *alt_char;
00938 struct match_char *next_char;
00939 struct ast_exten *exten;
00940 char x[1];
00941 };
00942
00943 struct scoreboard
00944 {
00945 int total_specificity;
00946 int total_length;
00947 char last_char;
00948 int canmatch;
00949 struct match_char *node;
00950 struct ast_exten *canmatch_exten;
00951 struct ast_exten *exten;
00952 };
00953
00954
00955 struct ast_context {
00956 ast_rwlock_t lock;
00957 struct ast_exten *root;
00958 struct ast_hashtab *root_table;
00959 struct match_char *pattern_tree;
00960 struct ast_context *next;
00961 struct ast_include *includes;
00962 struct ast_ignorepat *ignorepats;
00963 char *registrar;
00964 int refcount;
00965 AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
00966 ast_mutex_t macrolock;
00967 char name[0];
00968 };
00969
00970
00971 struct ast_app {
00972 int (*execute)(struct ast_channel *chan, const char *data);
00973 AST_DECLARE_STRING_FIELDS(
00974 AST_STRING_FIELD(synopsis);
00975 AST_STRING_FIELD(description);
00976 AST_STRING_FIELD(syntax);
00977 AST_STRING_FIELD(arguments);
00978 AST_STRING_FIELD(seealso);
00979 );
00980 #ifdef AST_XML_DOCS
00981 enum ast_doc_src docsrc;
00982 #endif
00983 AST_RWLIST_ENTRY(ast_app) list;
00984 struct ast_module *module;
00985 char name[0];
00986 };
00987
00988
00989 struct ast_state_cb {
00990
00991 int id;
00992
00993 void *data;
00994
00995 ast_state_cb_type change_cb;
00996
00997 ast_state_cb_destroy_type destroy_cb;
00998
00999 AST_LIST_ENTRY(ast_state_cb) entry;
01000 };
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010 struct ast_hint {
01011
01012
01013
01014
01015
01016
01017 struct ast_exten *exten;
01018 struct ao2_container *callbacks;
01019 int laststate;
01020 char context_name[AST_MAX_CONTEXT];
01021 char exten_name[AST_MAX_EXTENSION];
01022 };
01023
01024
01025 #ifdef LOW_MEMORY
01026 #define HASH_EXTENHINT_SIZE 17
01027 #else
01028 #define HASH_EXTENHINT_SIZE 563
01029 #endif
01030
01031 static const struct cfextension_states {
01032 int extension_state;
01033 const char * const text;
01034 } extension_states[] = {
01035 { AST_EXTENSION_NOT_INUSE, "Idle" },
01036 { AST_EXTENSION_INUSE, "InUse" },
01037 { AST_EXTENSION_BUSY, "Busy" },
01038 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
01039 { AST_EXTENSION_RINGING, "Ringing" },
01040 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
01041 { AST_EXTENSION_ONHOLD, "Hold" },
01042 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
01043 };
01044
01045 struct statechange {
01046 AST_LIST_ENTRY(statechange) entry;
01047 char dev[0];
01048 };
01049
01050 struct pbx_exception {
01051 AST_DECLARE_STRING_FIELDS(
01052 AST_STRING_FIELD(context);
01053 AST_STRING_FIELD(exten);
01054 AST_STRING_FIELD(reason);
01055 );
01056
01057 int priority;
01058 };
01059
01060 static int pbx_builtin_answer(struct ast_channel *, const char *);
01061 static int pbx_builtin_goto(struct ast_channel *, const char *);
01062 static int pbx_builtin_hangup(struct ast_channel *, const char *);
01063 static int pbx_builtin_background(struct ast_channel *, const char *);
01064 static int pbx_builtin_wait(struct ast_channel *, const char *);
01065 static int pbx_builtin_waitexten(struct ast_channel *, const char *);
01066 static int pbx_builtin_incomplete(struct ast_channel *, const char *);
01067 static int pbx_builtin_resetcdr(struct ast_channel *, const char *);
01068 static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
01069 static int pbx_builtin_ringing(struct ast_channel *, const char *);
01070 static int pbx_builtin_proceeding(struct ast_channel *, const char *);
01071 static int pbx_builtin_progress(struct ast_channel *, const char *);
01072 static int pbx_builtin_congestion(struct ast_channel *, const char *);
01073 static int pbx_builtin_busy(struct ast_channel *, const char *);
01074 static int pbx_builtin_noop(struct ast_channel *, const char *);
01075 static int pbx_builtin_gotoif(struct ast_channel *, const char *);
01076 static int pbx_builtin_gotoiftime(struct ast_channel *, const char *);
01077 static int pbx_builtin_execiftime(struct ast_channel *, const char *);
01078 static int pbx_builtin_saynumber(struct ast_channel *, const char *);
01079 static int pbx_builtin_saydigits(struct ast_channel *, const char *);
01080 static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
01081 static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
01082 static int pbx_builtin_saydate(struct ast_channel *, const char *);
01083 static int pbx_builtin_saytime(struct ast_channel *, const char *);
01084 static int matchcid(const char *cidpattern, const char *callerid);
01085 #ifdef NEED_DEBUG
01086 static void log_match_char_tree(struct match_char *node, char *prefix);
01087 #endif
01088 static int pbx_builtin_importvar(struct ast_channel *, const char *);
01089 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
01090 static void new_find_extension(const char *str, struct scoreboard *score,
01091 struct match_char *tree, int length, int spec, const char *callerid,
01092 const char *label, enum ext_match_t action);
01093 static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
01094 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
01095 struct ast_exten *e1, int findonly);
01096 static void create_match_char_tree(struct ast_context *con);
01097 static struct ast_exten *get_canmatch_exten(struct match_char *node);
01098 static void destroy_pattern_tree(struct match_char *pattern_tree);
01099 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
01100 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
01101 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
01102 static unsigned int hashtab_hash_extens(const void *obj);
01103 static unsigned int hashtab_hash_priority(const void *obj);
01104 static unsigned int hashtab_hash_labels(const void *obj);
01105 static void __ast_internal_context_destroy( struct ast_context *con);
01106 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
01107 int priority, const char *label, const char *callerid,
01108 const char *application, void *data, void (*datad)(void *), const char *registrar);
01109 static int ast_add_extension2_lockopt(struct ast_context *con,
01110 int replace, const char *extension, int priority, const char *label, const char *callerid,
01111 const char *application, void *data, void (*datad)(void *),
01112 const char *registrar, int lock_context);
01113 static struct ast_context *find_context_locked(const char *context);
01114 static struct ast_context *find_context(const char *context);
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127 static int compare_char(const void *a, const void *b)
01128 {
01129 const unsigned char *ac = a;
01130 const unsigned char *bc = b;
01131
01132 return *ac - *bc;
01133 }
01134
01135
01136 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
01137 {
01138 const struct ast_context *ac = ah_a;
01139 const struct ast_context *bc = ah_b;
01140 if (!ac || !bc)
01141 return 1;
01142
01143 return strcmp(ac->name, bc->name);
01144 }
01145
01146 static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
01147 {
01148 const struct ast_exten *ac = ah_a;
01149 const struct ast_exten *bc = ah_b;
01150 int x = strcmp(ac->exten, bc->exten);
01151 if (x) {
01152 return x;
01153 }
01154
01155
01156
01157 if (ac->matchcid == AST_EXT_MATCHCID_ANY || bc->matchcid == AST_EXT_MATCHCID_ANY) {
01158 return 0;
01159 }
01160 if (ac->matchcid == AST_EXT_MATCHCID_OFF && bc->matchcid == AST_EXT_MATCHCID_OFF) {
01161 return 0;
01162 }
01163 if (ac->matchcid != bc->matchcid) {
01164 return 1;
01165 }
01166
01167
01168 if (ast_strlen_zero(ac->cidmatch) && ast_strlen_zero(bc->cidmatch)) {
01169 return 0;
01170 }
01171 return strcmp(ac->cidmatch, bc->cidmatch);
01172 }
01173
01174 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
01175 {
01176 const struct ast_exten *ac = ah_a;
01177 const struct ast_exten *bc = ah_b;
01178 return ac->priority != bc->priority;
01179 }
01180
01181 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
01182 {
01183 const struct ast_exten *ac = ah_a;
01184 const struct ast_exten *bc = ah_b;
01185 return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
01186 }
01187
01188 unsigned int ast_hashtab_hash_contexts(const void *obj)
01189 {
01190 const struct ast_context *ac = obj;
01191 return ast_hashtab_hash_string(ac->name);
01192 }
01193
01194 static unsigned int hashtab_hash_extens(const void *obj)
01195 {
01196 const struct ast_exten *ac = obj;
01197 unsigned int x = ast_hashtab_hash_string(ac->exten);
01198 unsigned int y = 0;
01199 if (ac->matchcid == AST_EXT_MATCHCID_ON)
01200 y = ast_hashtab_hash_string(ac->cidmatch);
01201 return x+y;
01202 }
01203
01204 static unsigned int hashtab_hash_priority(const void *obj)
01205 {
01206 const struct ast_exten *ac = obj;
01207 return ast_hashtab_hash_int(ac->priority);
01208 }
01209
01210 static unsigned int hashtab_hash_labels(const void *obj)
01211 {
01212 const struct ast_exten *ac = obj;
01213 return ast_hashtab_hash_string(S_OR(ac->label, ""));
01214 }
01215
01216
01217 AST_RWLOCK_DEFINE_STATIC(globalslock);
01218 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
01219
01220 static int autofallthrough = 1;
01221 static int extenpatternmatchnew = 0;
01222 static char *overrideswitch = NULL;
01223
01224
01225 static struct ast_event_sub *device_state_sub;
01226
01227 AST_MUTEX_DEFINE_STATIC(maxcalllock);
01228 static int countcalls;
01229 static int totalcalls;
01230
01231 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
01232
01233
01234
01235
01236
01237 struct ast_custom_escalating_function {
01238 AST_RWLIST_ENTRY(ast_custom_escalating_function) list;
01239 const struct ast_custom_function *acf;
01240 unsigned int read_escalates:1;
01241 unsigned int write_escalates:1;
01242 };
01243
01244 static AST_RWLIST_HEAD_STATIC(escalation_root, ast_custom_escalating_function);
01245
01246
01247 static struct pbx_builtin {
01248 char name[AST_MAX_APP];
01249 int (*execute)(struct ast_channel *chan, const char *data);
01250 } builtins[] =
01251 {
01252
01253
01254
01255 { "Answer", pbx_builtin_answer },
01256 { "BackGround", pbx_builtin_background },
01257 { "Busy", pbx_builtin_busy },
01258 { "Congestion", pbx_builtin_congestion },
01259 { "ExecIfTime", pbx_builtin_execiftime },
01260 { "Goto", pbx_builtin_goto },
01261 { "GotoIf", pbx_builtin_gotoif },
01262 { "GotoIfTime", pbx_builtin_gotoiftime },
01263 { "ImportVar", pbx_builtin_importvar },
01264 { "Hangup", pbx_builtin_hangup },
01265 { "Incomplete", pbx_builtin_incomplete },
01266 { "NoOp", pbx_builtin_noop },
01267 { "Proceeding", pbx_builtin_proceeding },
01268 { "Progress", pbx_builtin_progress },
01269 { "RaiseException", pbx_builtin_raise_exception },
01270 { "ResetCDR", pbx_builtin_resetcdr },
01271 { "Ringing", pbx_builtin_ringing },
01272 { "SayAlpha", pbx_builtin_saycharacters },
01273 { "SayDigits", pbx_builtin_saydigits },
01274 { "SayNumber", pbx_builtin_saynumber },
01275 { "SayPhonetic", pbx_builtin_sayphonetic },
01276 { "SayDate", pbx_builtin_saydate },
01277 { "SayTime", pbx_builtin_saytime },
01278 { "Set", pbx_builtin_setvar },
01279 { "MSet", pbx_builtin_setvar_multiple },
01280 { "SetAMAFlags", pbx_builtin_setamaflags },
01281 { "Wait", pbx_builtin_wait },
01282 { "WaitExten", pbx_builtin_waitexten }
01283 };
01284
01285 static struct ast_context *contexts;
01286 static struct ast_hashtab *contexts_table = NULL;
01287
01288
01289
01290
01291
01292
01293
01294 AST_MUTEX_DEFINE_STATIC(conlock);
01295
01296
01297
01298
01299 AST_MUTEX_DEFINE_STATIC(context_merge_lock);
01300
01301 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
01302
01303 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
01304
01305 static int stateid = 1;
01306
01307
01308
01309
01310
01311
01312
01313
01314 static struct ao2_container *hints;
01315
01316 static struct ao2_container *statecbs;
01317
01318 #ifdef CONTEXT_DEBUG
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332 void check_contexts_trouble(void);
01333
01334 void check_contexts_trouble(void)
01335 {
01336 int x = 1;
01337 x = 2;
01338 }
01339
01340 int check_contexts(char *, int);
01341
01342 int check_contexts(char *file, int line )
01343 {
01344 struct ast_hashtab_iter *t1;
01345 struct ast_context *c1, *c2;
01346 int found = 0;
01347 struct ast_exten *e1, *e2, *e3;
01348 struct ast_exten ex;
01349
01350
01351
01352
01353 if (!contexts_table) {
01354 ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
01355 usleep(500000);
01356 }
01357
01358 t1 = ast_hashtab_start_traversal(contexts_table);
01359 while( (c1 = ast_hashtab_next(t1))) {
01360 for(c2=contexts;c2;c2=c2->next) {
01361 if (!strcmp(c1->name, c2->name)) {
01362 found = 1;
01363 break;
01364 }
01365 }
01366 if (!found) {
01367 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
01368 check_contexts_trouble();
01369 }
01370 }
01371 ast_hashtab_end_traversal(t1);
01372 for(c2=contexts;c2;c2=c2->next) {
01373 c1 = find_context_locked(c2->name);
01374 if (!c1) {
01375 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
01376 check_contexts_trouble();
01377 } else
01378 ast_unlock_contexts();
01379 }
01380
01381
01382
01383 for(c2=contexts;c2;c2=c2->next) {
01384 c1 = find_context_locked(c2->name);
01385 if (c1) {
01386 ast_unlock_contexts();
01387
01388
01389 for(e1 = c1->root; e1; e1=e1->next)
01390 {
01391 char dummy_name[1024];
01392 ex.exten = dummy_name;
01393 ex.matchcid = e1->matchcid;
01394 ex.cidmatch = e1->cidmatch;
01395 ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
01396 e2 = ast_hashtab_lookup(c1->root_table, &ex);
01397 if (!e2) {
01398 if (e1->matchcid == AST_EXT_MATCHCID_ON) {
01399 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
01400 } else {
01401 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
01402 }
01403 check_contexts_trouble();
01404 }
01405 }
01406
01407
01408 if (!c2->root_table) {
01409 if (c2->root) {
01410 ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
01411 usleep(500000);
01412 }
01413 } else {
01414 t1 = ast_hashtab_start_traversal(c2->root_table);
01415 while( (e2 = ast_hashtab_next(t1)) ) {
01416 for(e1=c2->root;e1;e1=e1->next) {
01417 if (!strcmp(e1->exten, e2->exten)) {
01418 found = 1;
01419 break;
01420 }
01421 }
01422 if (!found) {
01423 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
01424 check_contexts_trouble();
01425 }
01426
01427 }
01428 ast_hashtab_end_traversal(t1);
01429 }
01430 }
01431
01432
01433
01434
01435
01436 for(e1 = c2->root; e1; e1 = e1->next) {
01437
01438 for(e2=e1;e2;e2=e2->peer) {
01439 ex.priority = e2->priority;
01440 if (e2 != e1 && e2->peer_table) {
01441 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
01442 check_contexts_trouble();
01443 }
01444
01445 if (e2 != e1 && e2->peer_label_table) {
01446 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
01447 check_contexts_trouble();
01448 }
01449
01450 if (e2 == e1 && !e2->peer_table){
01451 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
01452 check_contexts_trouble();
01453 }
01454
01455 if (e2 == e1 && !e2->peer_label_table) {
01456 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
01457 check_contexts_trouble();
01458 }
01459
01460
01461 e3 = ast_hashtab_lookup(e1->peer_table, &ex);
01462 if (!e3) {
01463 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
01464 check_contexts_trouble();
01465 }
01466 }
01467
01468 if (!e1->peer_table){
01469 ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
01470 usleep(500000);
01471 }
01472
01473
01474 t1 = ast_hashtab_start_traversal(e1->peer_table);
01475 while( (e2 = ast_hashtab_next(t1)) ) {
01476 for(e3=e1;e3;e3=e3->peer) {
01477 if (e3->priority == e2->priority) {
01478 found = 1;
01479 break;
01480 }
01481 }
01482 if (!found) {
01483 ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
01484 check_contexts_trouble();
01485 }
01486 }
01487 ast_hashtab_end_traversal(t1);
01488 }
01489 }
01490 return 0;
01491 }
01492 #endif
01493
01494
01495
01496
01497 int pbx_exec(struct ast_channel *c,
01498 struct ast_app *app,
01499 const char *data)
01500 {
01501 int res;
01502 struct ast_module_user *u = NULL;
01503 const char *saved_c_appl;
01504 const char *saved_c_data;
01505
01506 if (c->cdr && !ast_check_hangup(c))
01507 ast_cdr_setapp(c->cdr, app->name, data);
01508
01509
01510 saved_c_appl= c->appl;
01511 saved_c_data= c->data;
01512
01513 c->appl = app->name;
01514 c->data = data;
01515 ast_cel_report_event(c, AST_CEL_APP_START, NULL, NULL, NULL);
01516
01517 if (app->module)
01518 u = __ast_module_user_add(app->module, c);
01519 if (strcasecmp(app->name, "system") && !ast_strlen_zero(data) &&
01520 strchr(data, '|') && !strchr(data, ',') && !ast_opt_dont_warn) {
01521 ast_log(LOG_WARNING, "The application delimiter is now the comma, not "
01522 "the pipe. Did you forget to convert your dialplan? (%s(%s))\n",
01523 app->name, (char *) data);
01524 }
01525 res = app->execute(c, S_OR(data, ""));
01526 if (app->module && u)
01527 __ast_module_user_remove(app->module, u);
01528 ast_cel_report_event(c, AST_CEL_APP_END, NULL, NULL, NULL);
01529
01530 c->appl = saved_c_appl;
01531 c->data = saved_c_data;
01532 return res;
01533 }
01534
01535
01536
01537 struct ast_app *pbx_findapp(const char *app)
01538 {
01539 struct ast_app *tmp;
01540
01541 AST_RWLIST_RDLOCK(&apps);
01542 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
01543 if (!strcasecmp(tmp->name, app))
01544 break;
01545 }
01546 AST_RWLIST_UNLOCK(&apps);
01547
01548 return tmp;
01549 }
01550
01551 static struct ast_switch *pbx_findswitch(const char *sw)
01552 {
01553 struct ast_switch *asw;
01554
01555 AST_RWLIST_RDLOCK(&switches);
01556 AST_RWLIST_TRAVERSE(&switches, asw, list) {
01557 if (!strcasecmp(asw->name, sw))
01558 break;
01559 }
01560 AST_RWLIST_UNLOCK(&switches);
01561
01562 return asw;
01563 }
01564
01565 static inline int include_valid(struct ast_include *i)
01566 {
01567 if (!i->hastime)
01568 return 1;
01569
01570 return ast_check_timing(&(i->timing));
01571 }
01572
01573 static void pbx_destroy(struct ast_pbx *p)
01574 {
01575 ast_free(p);
01576 }
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652 static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
01653 {
01654
01655
01656 if (deleted)
01657 return;
01658 board->total_specificity = spec;
01659 board->total_length = length;
01660 board->exten = exten;
01661 board->last_char = last;
01662 board->node = node;
01663 #ifdef NEED_DEBUG_HERE
01664 ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
01665 #endif
01666 }
01667
01668 #ifdef NEED_DEBUG
01669 static void log_match_char_tree(struct match_char *node, char *prefix)
01670 {
01671 char extenstr[40];
01672 struct ast_str *my_prefix = ast_str_alloca(1024);
01673
01674 extenstr[0] = '\0';
01675
01676 if (node && node->exten)
01677 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01678
01679 if (strlen(node->x) > 1) {
01680 ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
01681 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
01682 node->exten ? node->exten->exten : "", extenstr);
01683 } else {
01684 ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
01685 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
01686 node->exten ? node->exten->exten : "", extenstr);
01687 }
01688
01689 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
01690
01691 if (node->next_char)
01692 log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
01693
01694 if (node->alt_char)
01695 log_match_char_tree(node->alt_char, prefix);
01696 }
01697 #endif
01698
01699 static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
01700 {
01701 char extenstr[40];
01702 struct ast_str *my_prefix = ast_str_alloca(1024);
01703
01704 extenstr[0] = '\0';
01705
01706 if (node->exten) {
01707 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01708 }
01709
01710 if (strlen(node->x) > 1) {
01711 ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
01712 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
01713 node->exten ? node->exten->exten : "", extenstr);
01714 } else {
01715 ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
01716 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
01717 node->exten ? node->exten->exten : "", extenstr);
01718 }
01719
01720 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
01721
01722 if (node->next_char)
01723 cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
01724
01725 if (node->alt_char)
01726 cli_match_char_tree(node->alt_char, prefix, fd);
01727 }
01728
01729 static struct ast_exten *get_canmatch_exten(struct match_char *node)
01730 {
01731
01732 struct match_char *node2 = node;
01733
01734 for (node2 = node; node2; node2 = node2->next_char) {
01735 if (node2->exten) {
01736 #ifdef NEED_DEBUG_HERE
01737 ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
01738 #endif
01739 return node2->exten;
01740 }
01741 }
01742 #ifdef NEED_DEBUG_HERE
01743 ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
01744 #endif
01745 return 0;
01746 }
01747
01748 static struct ast_exten *trie_find_next_match(struct match_char *node)
01749 {
01750 struct match_char *m3;
01751 struct match_char *m4;
01752 struct ast_exten *e3;
01753
01754 if (node && node->x[0] == '.' && !node->x[1]) {
01755 return node->exten;
01756 }
01757
01758 if (node && node->x[0] == '!' && !node->x[1]) {
01759 return node->exten;
01760 }
01761
01762 if (!node || !node->next_char) {
01763 return NULL;
01764 }
01765
01766 m3 = node->next_char;
01767
01768 if (m3->exten) {
01769 return m3->exten;
01770 }
01771 for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
01772 if (m4->exten) {
01773 return m4->exten;
01774 }
01775 }
01776 for (m4 = m3; m4; m4 = m4->alt_char) {
01777 e3 = trie_find_next_match(m3);
01778 if (e3) {
01779 return e3;
01780 }
01781 }
01782
01783 return NULL;
01784 }
01785
01786 #ifdef DEBUG_THIS
01787 static char *action2str(enum ext_match_t action)
01788 {
01789 switch (action) {
01790 case E_MATCH:
01791 return "MATCH";
01792 case E_CANMATCH:
01793 return "CANMATCH";
01794 case E_MATCHMORE:
01795 return "MATCHMORE";
01796 case E_FINDLABEL:
01797 return "FINDLABEL";
01798 case E_SPAWN:
01799 return "SPAWN";
01800 default:
01801 return "?ACTION?";
01802 }
01803 }
01804
01805 #endif
01806
01807 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action)
01808 {
01809 struct match_char *p;
01810 struct ast_exten pattern = { .label = label };
01811 #ifdef DEBUG_THIS
01812 if (tree)
01813 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
01814 else
01815 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
01816 #endif
01817 for (p = tree; p; p = p->alt_char) {
01818 if (p->is_pattern) {
01819 if (p->x[0] == 'N') {
01820 if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
01821 #define NEW_MATCHER_CHK_MATCH \
01822 if (p->exten && !(*(str + 1))) { \
01823 if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { \
01824 update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
01825 if (!p->deleted) { \
01826 if (action == E_FINDLABEL) { \
01827 if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
01828 ast_debug(4, "Found label in preferred extension\n"); \
01829 return; \
01830 } \
01831 } else { \
01832 ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten); \
01833 return; \
01834 } \
01835 } \
01836 } \
01837 }
01838
01839 #define NEW_MATCHER_RECURSE \
01840 if (p->next_char && (*(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
01841 || p->next_char->x[0] == '!')) { \
01842 if (*(str + 1) || p->next_char->x[0] == '!') { \
01843 new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
01844 if (score->exten) { \
01845 ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten); \
01846 return; \
01847 } \
01848 } else { \
01849 new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
01850 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
01851 ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \
01852 "NULL"); \
01853 return; \
01854 } \
01855 } \
01856 } else if ((p->next_char || action == E_CANMATCH) && !*(str + 1)) { \
01857 score->canmatch = 1; \
01858 score->canmatch_exten = get_canmatch_exten(p); \
01859 if (action == E_CANMATCH || action == E_MATCHMORE) { \
01860 ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
01861 return; \
01862 } \
01863 }
01864
01865 NEW_MATCHER_CHK_MATCH;
01866 NEW_MATCHER_RECURSE;
01867 }
01868 } else if (p->x[0] == 'Z') {
01869 if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
01870 NEW_MATCHER_CHK_MATCH;
01871 NEW_MATCHER_RECURSE;
01872 }
01873 } else if (p->x[0] == 'X') {
01874 if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
01875 NEW_MATCHER_CHK_MATCH;
01876 NEW_MATCHER_RECURSE;
01877 }
01878 } else if (p->x[0] == '.' && p->x[1] == 0) {
01879
01880 int i = 0;
01881 const char *str2 = str;
01882 while (*str2 && *str2 != '/') {
01883 str2++;
01884 i++;
01885 }
01886 if (p->exten && *str2 != '/') {
01887 update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
01888 if (score->exten) {
01889 ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
01890 return;
01891 }
01892 }
01893 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01894 new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
01895 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01896 ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
01897 return;
01898 }
01899 }
01900 } else if (p->x[0] == '!' && p->x[1] == 0) {
01901
01902 int i = 1;
01903 const char *str2 = str;
01904 while (*str2 && *str2 != '/') {
01905 str2++;
01906 i++;
01907 }
01908 if (p->exten && *str2 != '/') {
01909 update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
01910 if (score->exten) {
01911 ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
01912 return;
01913 }
01914 }
01915 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01916 new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
01917 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01918 ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
01919 return;
01920 }
01921 }
01922 } else if (p->x[0] == '/' && p->x[1] == 0) {
01923
01924 if (p->next_char && callerid && *callerid) {
01925 new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
01926 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01927 ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
01928 return;
01929 }
01930 }
01931 } else if (strchr(p->x, *str)) {
01932 ast_debug(4, "Nothing strange about this match\n");
01933 NEW_MATCHER_CHK_MATCH;
01934 NEW_MATCHER_RECURSE;
01935 }
01936 } else if (strchr(p->x, *str)) {
01937 ast_debug(4, "Nothing strange about this match\n");
01938 NEW_MATCHER_CHK_MATCH;
01939 NEW_MATCHER_RECURSE;
01940 }
01941 }
01942 ast_debug(4, "return at end of func\n");
01943 }
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962 static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
01963 {
01964 struct match_char *t;
01965
01966 if (!current) {
01967 return 0;
01968 }
01969
01970 for (t = current; t; t = t->alt_char) {
01971 if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {
01972 return t;
01973 }
01974 }
01975
01976 return 0;
01977 }
01978
01979
01980
01981
01982
01983 static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
01984 {
01985 struct match_char *curr, *lcurr;
01986
01987
01988
01989 if (!(*parent_ptr)) {
01990 *parent_ptr = node;
01991 return;
01992 }
01993
01994 if ((*parent_ptr)->specificity > node->specificity) {
01995
01996 node->alt_char = (*parent_ptr);
01997 *parent_ptr = node;
01998 return;
01999 }
02000
02001 lcurr = *parent_ptr;
02002 for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
02003 if (curr->specificity > node->specificity) {
02004 node->alt_char = curr;
02005 lcurr->alt_char = node;
02006 break;
02007 }
02008 lcurr = curr;
02009 }
02010
02011 if (!curr) {
02012 lcurr->alt_char = node;
02013 }
02014
02015 }
02016
02017 struct pattern_node {
02018
02019 int specif;
02020
02021 char buf[256];
02022 };
02023
02024 static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, const struct pattern_node *pattern, int is_pattern, int already, struct match_char **nextcharptr)
02025 {
02026 struct match_char *m;
02027
02028 if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
02029 return NULL;
02030 }
02031
02032
02033
02034
02035 strcpy(m->x, pattern->buf);
02036
02037
02038
02039 m->is_pattern = is_pattern;
02040 if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
02041 m->specificity = 0x0832;
02042 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
02043 m->specificity = 0x0931;
02044 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
02045 m->specificity = 0x0a30;
02046 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
02047 m->specificity = 0x18000;
02048 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
02049 m->specificity = 0x28000;
02050 } else {
02051 m->specificity = pattern->specif;
02052 }
02053
02054 if (!con->pattern_tree) {
02055 insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
02056 } else {
02057 if (already) {
02058 insert_in_next_chars_alt_char_list(nextcharptr, m);
02059 } else {
02060 insert_in_next_chars_alt_char_list(¤t->next_char, m);
02061 }
02062 }
02063
02064 return m;
02065 }
02066
02067
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078 static const char *get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
02079 {
02080 #define INC_DST_OVERFLOW_CHECK \
02081 do { \
02082 if (dst - node->buf < sizeof(node->buf) - 1) { \
02083 ++dst; \
02084 } else { \
02085 overflow = 1; \
02086 } \
02087 } while (0)
02088
02089 node->specif = 0;
02090 node->buf[0] = '\0';
02091 while (*src) {
02092 if (*src == '[' && pattern) {
02093 char *dst = node->buf;
02094 const char *src_next;
02095 int length;
02096 int overflow = 0;
02097
02098
02099 ++src;
02100 for (;;) {
02101 if (*src == '\\') {
02102
02103 ++src;
02104 if (*src == '[' || *src == '\\' || *src == '-' || *src == ']') {
02105 *dst = *src++;
02106 INC_DST_OVERFLOW_CHECK;
02107 }
02108 } else if (*src == '-') {
02109 unsigned char first;
02110 unsigned char last;
02111
02112 src_next = src;
02113 first = *(src_next - 1);
02114 last = *++src_next;
02115
02116 if (last == '\\') {
02117
02118 last = *++src_next;
02119 }
02120
02121
02122 if (node->buf[0] && last) {
02123
02124 while (++first <= last) {
02125 *dst = first;
02126 INC_DST_OVERFLOW_CHECK;
02127 }
02128 src = src_next + 1;
02129 } else {
02130
02131
02132
02133
02134 *dst = *src++;
02135 INC_DST_OVERFLOW_CHECK;
02136 }
02137 } else if (*src == '\0') {
02138 ast_log(LOG_WARNING,
02139 "A matching ']' was not found for '[' in exten pattern '%s'\n",
02140 extenbuf);
02141 break;
02142 } else if (*src == ']') {
02143 ++src;
02144 break;
02145 } else {
02146 *dst = *src++;
02147 INC_DST_OVERFLOW_CHECK;
02148 }
02149 }
02150
02151 *dst = '\0';
02152
02153 if (overflow) {
02154 ast_log(LOG_ERROR,
02155 "Expanded character set too large to deal with in exten pattern '%s'. Ignoring character set.\n",
02156 extenbuf);
02157 node->buf[0] = '\0';
02158 continue;
02159 }
02160
02161
02162 length = strlen(node->buf);
02163 if (!length) {
02164 ast_log(LOG_WARNING, "Empty character set in exten pattern '%s'. Ignoring.\n",
02165 extenbuf);
02166 node->buf[0] = '\0';
02167 continue;
02168 }
02169 qsort(node->buf, length, 1, compare_char);
02170
02171
02172 dst = node->buf;
02173 src_next = node->buf;
02174 while (*src_next++) {
02175 if (*dst != *src_next) {
02176 *++dst = *src_next;
02177 }
02178 }
02179
02180 length = strlen(node->buf);
02181 length <<= 8;
02182 node->specif = length | (unsigned char) node->buf[0];
02183 break;
02184 } else if (*src == '-') {
02185
02186 ++src;
02187 } else {
02188 if (*src == '\\') {
02189
02190
02191
02192
02193
02194 node->buf[0] = *++src;
02195 if (!node->buf[0]) {
02196 break;
02197 }
02198 } else {
02199 node->buf[0] = *src;
02200 if (pattern) {
02201
02202 if (node->buf[0] == 'n') {
02203 node->buf[0] = 'N';
02204 } else if (node->buf[0] == 'x') {
02205 node->buf[0] = 'X';
02206 } else if (node->buf[0] == 'z') {
02207 node->buf[0] = 'Z';
02208 }
02209 }
02210 }
02211 node->buf[1] = '\0';
02212 node->specif = 1;
02213 ++src;
02214 break;
02215 }
02216 }
02217 return src;
02218
02219 #undef INC_DST_OVERFLOW_CHECK
02220 }
02221
02222 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
02223 {
02224 struct match_char *m1 = NULL;
02225 struct match_char *m2 = NULL;
02226 struct match_char **m0;
02227 const char *pos;
02228 int already;
02229 int pattern = 0;
02230 int idx_cur;
02231 int idx_next;
02232 char extenbuf[512];
02233 struct pattern_node pat_node[2];
02234
02235 if (e1->matchcid) {
02236 if (sizeof(extenbuf) < strlen(e1->exten) + strlen(e1->cidmatch) + 2) {
02237 ast_log(LOG_ERROR,
02238 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
02239 e1->exten, e1->cidmatch);
02240 return NULL;
02241 }
02242 sprintf(extenbuf, "%s/%s", e1->exten, e1->cidmatch);
02243 } else {
02244 ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
02245 }
02246
02247 #ifdef NEED_DEBUG
02248 ast_log(LOG_DEBUG, "Adding exten %s to tree\n", extenbuf);
02249 #endif
02250 m1 = con->pattern_tree;
02251 m0 = &con->pattern_tree;
02252 already = 1;
02253
02254 pos = extenbuf;
02255 if (*pos == '_') {
02256 pattern = 1;
02257 ++pos;
02258 }
02259 idx_cur = 0;
02260 pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
02261 for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
02262 idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
02263 pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
02264
02265
02266 m2 = NULL;
02267 if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].buf, pattern))
02268 && m2->next_char) {
02269 if (!pat_node[idx_next].buf[0]) {
02270
02271
02272
02273
02274
02275 if (findonly) {
02276 return m2;
02277 }
02278 if (m2->exten) {
02279 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
02280 m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
02281 }
02282 m2->exten = e1;
02283 m2->deleted = 0;
02284 }
02285 m1 = m2->next_char;
02286 m0 = &m2->next_char;
02287 } else {
02288 if (m2) {
02289 if (findonly) {
02290 return m2;
02291 }
02292 m1 = m2;
02293 } else {
02294 if (findonly) {
02295 return m1;
02296 }
02297 m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
02298 if (!m1) {
02299 return NULL;
02300 }
02301 m0 = &m1->next_char;
02302 }
02303 if (!pat_node[idx_next].buf[0]) {
02304 if (m2 && m2->exten) {
02305 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
02306 m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
02307 }
02308 m1->deleted = 0;
02309 m1->exten = e1;
02310 }
02311
02312
02313
02314
02315 already = 0;
02316 }
02317 }
02318 return m1;
02319 }
02320
02321 static void create_match_char_tree(struct ast_context *con)
02322 {
02323 struct ast_hashtab_iter *t1;
02324 struct ast_exten *e1;
02325 #ifdef NEED_DEBUG
02326 int biggest_bucket, resizes, numobjs, numbucks;
02327
02328 ast_log(LOG_DEBUG,"Creating Extension Trie for context %s(%p)\n", con->name, con);
02329 ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
02330 ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
02331 numobjs, numbucks, biggest_bucket, resizes);
02332 #endif
02333 t1 = ast_hashtab_start_traversal(con->root_table);
02334 while ((e1 = ast_hashtab_next(t1))) {
02335 if (e1->exten) {
02336 add_exten_to_pattern_tree(con, e1, 0);
02337 } else {
02338 ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
02339 }
02340 }
02341 ast_hashtab_end_traversal(t1);
02342 }
02343
02344 static void destroy_pattern_tree(struct match_char *pattern_tree)
02345 {
02346
02347 if (pattern_tree->alt_char) {
02348 destroy_pattern_tree(pattern_tree->alt_char);
02349 pattern_tree->alt_char = 0;
02350 }
02351
02352 if (pattern_tree->next_char) {
02353 destroy_pattern_tree(pattern_tree->next_char);
02354 pattern_tree->next_char = 0;
02355 }
02356 pattern_tree->exten = 0;
02357 ast_free(pattern_tree);
02358 }
02359
02360
02361
02362
02363
02364
02365
02366
02367
02368 static int ext_cmp_exten_strlen(const char *str)
02369 {
02370 int len;
02371
02372 len = 0;
02373 for (;;) {
02374
02375 while (*str == '-') {
02376 ++str;
02377 }
02378 if (!*str) {
02379 break;
02380 }
02381 ++str;
02382 ++len;
02383 }
02384 return len;
02385 }
02386
02387
02388
02389
02390
02391
02392
02393
02394
02395
02396
02397
02398 static int ext_cmp_exten_partial(const char *left, const char *right)
02399 {
02400 int cmp;
02401
02402 for (;;) {
02403
02404 while (*left == '-') {
02405 ++left;
02406 }
02407 while (*right == '-') {
02408 ++right;
02409 }
02410
02411 if (!*right) {
02412
02413
02414
02415
02416 cmp = 0;
02417 break;
02418 }
02419
02420 cmp = *left - *right;
02421 if (cmp) {
02422 break;
02423 }
02424 ++left;
02425 ++right;
02426 }
02427 return cmp;
02428 }
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441 static int ext_cmp_exten(const char *left, const char *right)
02442 {
02443 int cmp;
02444
02445 for (;;) {
02446
02447 while (*left == '-') {
02448 ++left;
02449 }
02450 while (*right == '-') {
02451 ++right;
02452 }
02453
02454 cmp = *left - *right;
02455 if (cmp) {
02456 break;
02457 }
02458 if (!*left) {
02459
02460
02461
02462
02463 break;
02464 }
02465 ++left;
02466 ++right;
02467 }
02468 return cmp;
02469 }
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499
02500
02501
02502
02503
02504
02505
02506
02507
02508
02509
02510
02511
02512
02513
02514
02515
02516
02517
02518
02519
02520
02521
02522
02523
02524
02525
02526
02527
02528 static int ext_cmp_pattern_pos(const char **p, unsigned char *bitwise)
02529 {
02530 #define BITS_PER 8
02531 unsigned char c;
02532 unsigned char cmin;
02533 int count;
02534 const char *end;
02535
02536 do {
02537
02538 do {
02539 c = *(*p)++;
02540 } while (c == '-');
02541
02542
02543 switch (c) {
02544 default:
02545
02546 bitwise[c / BITS_PER] = 1 << ((BITS_PER - 1) - (c % BITS_PER));
02547 return 0x0100 | c;
02548
02549 case 'n':
02550 case 'N':
02551
02552 bitwise[6] = 0x3f;
02553 bitwise[7] = 0xc0;
02554 return 0x0800 | '2';
02555
02556 case 'x':
02557 case 'X':
02558
02559 bitwise[6] = 0xff;
02560 bitwise[7] = 0xc0;
02561 return 0x0A00 | '0';
02562
02563 case 'z':
02564 case 'Z':
02565
02566 bitwise[6] = 0x7f;
02567 bitwise[7] = 0xc0;
02568 return 0x0900 | '1';
02569
02570 case '.':
02571
02572 return 0x18000;
02573
02574 case '!':
02575
02576 return 0x28000;
02577
02578 case '\0':
02579
02580 *p = NULL;
02581 return 0x30000;
02582
02583 case '[':
02584
02585 break;
02586 }
02587
02588 end = strchr(*p, ']');
02589
02590 if (!end) {
02591 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02592 return 0x40000;
02593 }
02594
02595 count = 0;
02596 cmin = 0xFF;
02597 for (; *p < end; ++*p) {
02598 unsigned char c1;
02599 unsigned char c2;
02600
02601 c1 = (*p)[0];
02602 if (*p + 2 < end && (*p)[1] == '-') {
02603 c2 = (*p)[2];
02604 *p += 2;
02605 } else {
02606 c2 = c1;
02607 }
02608 if (c1 < cmin) {
02609 cmin = c1;
02610 }
02611 for (; c1 <= c2; ++c1) {
02612 unsigned char mask = 1 << ((BITS_PER - 1) - (c1 % BITS_PER));
02613
02614
02615
02616
02617
02618
02619
02620 if (!(bitwise[c1 / BITS_PER] & mask)) {
02621
02622 bitwise[c1 / BITS_PER] |= mask;
02623 count += 0x100;
02624 }
02625 }
02626 }
02627 ++*p;
02628 } while (!count);
02629 return count | cmin;
02630 }
02631
02632
02633
02634
02635
02636
02637
02638
02639
02640
02641
02642
02643 static int ext_cmp_pattern(const char *left, const char *right)
02644 {
02645 int cmp;
02646 int left_pos;
02647 int right_pos;
02648
02649 for (;;) {
02650 unsigned char left_bitwise[32] = { 0, };
02651 unsigned char right_bitwise[32] = { 0, };
02652
02653 left_pos = ext_cmp_pattern_pos(&left, left_bitwise);
02654 right_pos = ext_cmp_pattern_pos(&right, right_bitwise);
02655 cmp = left_pos - right_pos;
02656 if (!cmp) {
02657
02658
02659
02660
02661
02662
02663
02664 cmp = memcmp(right_bitwise, left_bitwise, ARRAY_LEN(left_bitwise));
02665 }
02666 if (cmp) {
02667 break;
02668 }
02669 if (!left) {
02670
02671
02672
02673
02674 break;
02675 }
02676 }
02677 return cmp;
02678 }
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691 static int ext_cmp(const char *left, const char *right)
02692 {
02693
02694 if (left[0] != '_') {
02695 if (right[0] == '_') {
02696 return -1;
02697 }
02698
02699 return ext_cmp_exten(left, right);
02700 }
02701 if (right[0] != '_') {
02702 return 1;
02703 }
02704
02705
02706
02707
02708
02709
02710 return ext_cmp_pattern(left + 1, right + 1);
02711 }
02712
02713 int ast_extension_cmp(const char *a, const char *b)
02714 {
02715 int cmp;
02716
02717 cmp = ext_cmp(a, b);
02718 if (cmp < 0) {
02719 return -1;
02720 }
02721 if (cmp > 0) {
02722 return 1;
02723 }
02724 return 0;
02725 }
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
02740 {
02741 mode &= E_MATCH_MASK;
02742
02743 #ifdef NEED_DEBUG_HERE
02744 ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
02745 #endif
02746
02747 if (pattern[0] != '_') {
02748 int lp = ext_cmp_exten_strlen(pattern);
02749 int ld = ext_cmp_exten_strlen(data);
02750
02751 if (lp < ld) {
02752 #ifdef NEED_DEBUG_HERE
02753 ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
02754 #endif
02755 return 0;
02756 }
02757
02758 if (mode == E_MATCH) {
02759 #ifdef NEED_DEBUG_HERE
02760 ast_log(LOG_NOTICE,"return (!ext_cmp_exten(%s,%s) when mode== E_MATCH)\n", pattern, data);
02761 #endif
02762 return !ext_cmp_exten(pattern, data);
02763 }
02764 if (ld == 0 || !ext_cmp_exten_partial(pattern, data)) {
02765 #ifdef NEED_DEBUG_HERE
02766 ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
02767 #endif
02768 return (mode == E_MATCHMORE) ? lp > ld : 1;
02769 } else {
02770 #ifdef NEED_DEBUG_HERE
02771 ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
02772 #endif
02773 return 0;
02774 }
02775 }
02776 if (mode == E_MATCH && data[0] == '_') {
02777
02778
02779
02780
02781
02782
02783
02784
02785
02786 #ifdef NEED_DEBUG_HERE
02787 ast_log(LOG_NOTICE, "Comparing as patterns first. pattern:%s data:%s\n", pattern, data);
02788 #endif
02789 if (!ext_cmp_pattern(pattern + 1, data + 1)) {
02790 #ifdef NEED_DEBUG_HERE
02791 ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
02792 #endif
02793 return 1;
02794 }
02795 }
02796
02797 ++pattern;
02798
02799
02800
02801
02802 for (;;) {
02803 const char *end;
02804
02805
02806 while (*data == '-') {
02807 ++data;
02808 }
02809 while (*pattern == '-') {
02810 ++pattern;
02811 }
02812 if (!*data || !*pattern || *pattern == '/') {
02813 break;
02814 }
02815
02816 switch (*pattern) {
02817 case '[':
02818 ++pattern;
02819 end = strchr(pattern, ']');
02820 if (!end) {
02821 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02822 return 0;
02823 }
02824 if (pattern == end) {
02825
02826 ++pattern;
02827 continue;
02828 }
02829 for (; pattern < end; ++pattern) {
02830 if (pattern+2 < end && pattern[1] == '-') {
02831 if (*data >= pattern[0] && *data <= pattern[2])
02832 break;
02833 else {
02834 pattern += 2;
02835 continue;
02836 }
02837 } else if (*data == pattern[0])
02838 break;
02839 }
02840 if (pattern >= end) {
02841 #ifdef NEED_DEBUG_HERE
02842 ast_log(LOG_NOTICE,"return (0) when pattern>=end\n");
02843 #endif
02844 return 0;
02845 }
02846 pattern = end;
02847 break;
02848 case 'n':
02849 case 'N':
02850 if (*data < '2' || *data > '9') {
02851 #ifdef NEED_DEBUG_HERE
02852 ast_log(LOG_NOTICE,"return (0) N is not matched\n");
02853 #endif
02854 return 0;
02855 }
02856 break;
02857 case 'x':
02858 case 'X':
02859 if (*data < '0' || *data > '9') {
02860 #ifdef NEED_DEBUG_HERE
02861 ast_log(LOG_NOTICE,"return (0) X is not matched\n");
02862 #endif
02863 return 0;
02864 }
02865 break;
02866 case 'z':
02867 case 'Z':
02868 if (*data < '1' || *data > '9') {
02869 #ifdef NEED_DEBUG_HERE
02870 ast_log(LOG_NOTICE,"return (0) Z is not matched\n");
02871 #endif
02872 return 0;
02873 }
02874 break;
02875 case '.':
02876 #ifdef NEED_DEBUG_HERE
02877 ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
02878 #endif
02879 return 1;
02880 case '!':
02881 #ifdef NEED_DEBUG_HERE
02882 ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
02883 #endif
02884 return 2;
02885 default:
02886 if (*data != *pattern) {
02887 #ifdef NEED_DEBUG_HERE
02888 ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
02889 #endif
02890 return 0;
02891 }
02892 break;
02893 }
02894 ++data;
02895 ++pattern;
02896 }
02897 if (*data) {
02898 #ifdef NEED_DEBUG_HERE
02899 ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
02900 #endif
02901 return 0;
02902 }
02903
02904
02905
02906
02907
02908 if (*pattern == '\0' || *pattern == '/') {
02909 #ifdef NEED_DEBUG_HERE
02910 ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
02911 #endif
02912 return (mode == E_MATCHMORE) ? 0 : 1;
02913 } else if (*pattern == '!') {
02914 #ifdef NEED_DEBUG_HERE
02915 ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
02916 #endif
02917 return 2;
02918 } else {
02919 #ifdef NEED_DEBUG_HERE
02920 ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
02921 #endif
02922 return (mode == E_MATCH) ? 0 : 1;
02923 }
02924 }
02925
02926
02927
02928
02929
02930 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
02931 {
02932 int i;
02933 static int prof_id = -2;
02934 if (prof_id == -2) {
02935 prof_id = ast_add_profile("ext_match", 0);
02936 }
02937 ast_mark(prof_id, 1);
02938 i = _extension_match_core(ast_strlen_zero(pattern) ? "" : pattern, ast_strlen_zero(data) ? "" : data, mode);
02939 ast_mark(prof_id, 0);
02940 return i;
02941 }
02942
02943 int ast_extension_match(const char *pattern, const char *data)
02944 {
02945 return extension_match_core(pattern, data, E_MATCH);
02946 }
02947
02948 int ast_extension_close(const char *pattern, const char *data, int needmore)
02949 {
02950 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
02951 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
02952 return extension_match_core(pattern, data, needmore);
02953 }
02954
02955 struct fake_context
02956 {
02957 ast_rwlock_t lock;
02958 struct ast_exten *root;
02959 struct ast_hashtab *root_table;
02960 struct match_char *pattern_tree;
02961 struct ast_context *next;
02962 struct ast_include *includes;
02963 struct ast_ignorepat *ignorepats;
02964 const char *registrar;
02965 int refcount;
02966 AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
02967 ast_mutex_t macrolock;
02968 char name[256];
02969 };
02970
02971 struct ast_context *ast_context_find(const char *name)
02972 {
02973 struct ast_context *tmp;
02974 struct fake_context item;
02975
02976 if (!name) {
02977 return NULL;
02978 }
02979 ast_rdlock_contexts();
02980 if (contexts_table) {
02981 ast_copy_string(item.name, name, sizeof(item.name));
02982 tmp = ast_hashtab_lookup(contexts_table, &item);
02983 } else {
02984 tmp = NULL;
02985 while ((tmp = ast_walk_contexts(tmp))) {
02986 if (!strcasecmp(name, tmp->name)) {
02987 break;
02988 }
02989 }
02990 }
02991 ast_unlock_contexts();
02992 return tmp;
02993 }
02994
02995 #define STATUS_NO_CONTEXT 1
02996 #define STATUS_NO_EXTENSION 2
02997 #define STATUS_NO_PRIORITY 3
02998 #define STATUS_NO_LABEL 4
02999 #define STATUS_SUCCESS 5
03000
03001 static int matchcid(const char *cidpattern, const char *callerid)
03002 {
03003
03004
03005
03006 if (ast_strlen_zero(callerid)) {
03007 return ast_strlen_zero(cidpattern) ? 1 : 0;
03008 }
03009
03010 return ast_extension_match(cidpattern, callerid);
03011 }
03012
03013 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
03014 struct ast_context *bypass, struct pbx_find_info *q,
03015 const char *context, const char *exten, int priority,
03016 const char *label, const char *callerid, enum ext_match_t action)
03017 {
03018 int x, res;
03019 struct ast_context *tmp = NULL;
03020 struct ast_exten *e = NULL, *eroot = NULL;
03021 struct ast_include *i = NULL;
03022 struct ast_sw *sw = NULL;
03023 struct ast_exten pattern = {NULL, };
03024 struct scoreboard score = {0, };
03025 struct ast_str *tmpdata = NULL;
03026
03027 pattern.label = label;
03028 pattern.priority = priority;
03029 #ifdef NEED_DEBUG_HERE
03030 ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
03031 #endif
03032
03033
03034 if (q->stacklen == 0) {
03035 q->status = STATUS_NO_CONTEXT;
03036 q->swo = NULL;
03037 q->data = NULL;
03038 q->foundcontext = NULL;
03039 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
03040 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
03041 return NULL;
03042 }
03043
03044
03045 for (x = 0; x < q->stacklen; x++) {
03046 if (!strcasecmp(q->incstack[x], context))
03047 return NULL;
03048 }
03049
03050 if (bypass) {
03051 tmp = bypass;
03052 } else {
03053 tmp = find_context(context);
03054 if (!tmp) {
03055 return NULL;
03056 }
03057 }
03058
03059 if (q->status < STATUS_NO_EXTENSION)
03060 q->status = STATUS_NO_EXTENSION;
03061
03062
03063
03064 eroot = NULL;
03065 score.total_specificity = 0;
03066 score.exten = 0;
03067 score.total_length = 0;
03068 if (!tmp->pattern_tree && tmp->root_table) {
03069 create_match_char_tree(tmp);
03070 #ifdef NEED_DEBUG
03071 ast_log(LOG_DEBUG, "Tree Created in context %s:\n", context);
03072 log_match_char_tree(tmp->pattern_tree," ");
03073 #endif
03074 }
03075 #ifdef NEED_DEBUG
03076 ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
03077 log_match_char_tree(tmp->pattern_tree, ":: ");
03078 #endif
03079
03080 do {
03081 if (!ast_strlen_zero(overrideswitch)) {
03082 char *osw = ast_strdupa(overrideswitch), *name;
03083 struct ast_switch *asw;
03084 ast_switch_f *aswf = NULL;
03085 char *datap;
03086 int eval = 0;
03087
03088 name = strsep(&osw, "/");
03089 asw = pbx_findswitch(name);
03090
03091 if (!asw) {
03092 ast_log(LOG_WARNING, "No such switch '%s'\n", name);
03093 break;
03094 }
03095
03096 if (osw && strchr(osw, '$')) {
03097 eval = 1;
03098 }
03099
03100 if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
03101 ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!\n");
03102 break;
03103 } else if (eval) {
03104
03105 pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
03106 datap = ast_str_buffer(tmpdata);
03107 } else {
03108 datap = osw;
03109 }
03110
03111
03112 if (action == E_CANMATCH)
03113 aswf = asw->canmatch;
03114 else if (action == E_MATCHMORE)
03115 aswf = asw->matchmore;
03116 else
03117 aswf = asw->exists;
03118 if (!aswf) {
03119 res = 0;
03120 } else {
03121 if (chan) {
03122 ast_autoservice_start(chan);
03123 }
03124 res = aswf(chan, context, exten, priority, callerid, datap);
03125 if (chan) {
03126 ast_autoservice_stop(chan);
03127 }
03128 }
03129 if (res) {
03130 q->swo = asw;
03131 q->data = datap;
03132 q->foundcontext = context;
03133
03134 return NULL;
03135 }
03136 }
03137 } while (0);
03138
03139 if (extenpatternmatchnew) {
03140 new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
03141 eroot = score.exten;
03142
03143 if (score.last_char == '!' && action == E_MATCHMORE) {
03144
03145
03146
03147 #ifdef NEED_DEBUG_HERE
03148 ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
03149 #endif
03150 return NULL;
03151 }
03152
03153 if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
03154 q->status = STATUS_SUCCESS;
03155 #ifdef NEED_DEBUG_HERE
03156 ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
03157 #endif
03158 return score.canmatch_exten;
03159 }
03160
03161 if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
03162 if (score.node) {
03163 struct ast_exten *z = trie_find_next_match(score.node);
03164 if (z) {
03165 #ifdef NEED_DEBUG_HERE
03166 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
03167 #endif
03168 } else {
03169 if (score.canmatch_exten) {
03170 #ifdef NEED_DEBUG_HERE
03171 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
03172 #endif
03173 return score.canmatch_exten;
03174 } else {
03175 #ifdef NEED_DEBUG_HERE
03176 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
03177 #endif
03178 }
03179 }
03180 return z;
03181 }
03182 #ifdef NEED_DEBUG_HERE
03183 ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
03184 #endif
03185 return NULL;
03186 }
03187
03188 if (eroot) {
03189
03190 if (q->status < STATUS_NO_PRIORITY)
03191 q->status = STATUS_NO_PRIORITY;
03192 e = NULL;
03193 if (action == E_FINDLABEL && label ) {
03194 if (q->status < STATUS_NO_LABEL)
03195 q->status = STATUS_NO_LABEL;
03196 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
03197 } else {
03198 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
03199 }
03200 if (e) {
03201 q->status = STATUS_SUCCESS;
03202 q->foundcontext = context;
03203 #ifdef NEED_DEBUG_HERE
03204 ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
03205 #endif
03206 return e;
03207 }
03208 }
03209 } else {
03210
03211
03212 eroot = NULL;
03213 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
03214 int match = extension_match_core(eroot->exten, exten, action);
03215
03216
03217 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
03218 continue;
03219 if (match == 2 && action == E_MATCHMORE) {
03220
03221
03222
03223 return NULL;
03224 }
03225
03226 if (q->status < STATUS_NO_PRIORITY)
03227 q->status = STATUS_NO_PRIORITY;
03228 e = NULL;
03229 if (action == E_FINDLABEL && label ) {
03230 if (q->status < STATUS_NO_LABEL)
03231 q->status = STATUS_NO_LABEL;
03232 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
03233 } else {
03234 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
03235 }
03236 if (e) {
03237 q->status = STATUS_SUCCESS;
03238 q->foundcontext = context;
03239 return e;
03240 }
03241 }
03242 }
03243
03244
03245 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
03246 struct ast_switch *asw = pbx_findswitch(sw->name);
03247 ast_switch_f *aswf = NULL;
03248 char *datap;
03249
03250 if (!asw) {
03251 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
03252 continue;
03253 }
03254
03255
03256 if (sw->eval) {
03257 if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
03258 ast_log(LOG_WARNING, "Can't evaluate switch?!\n");
03259 continue;
03260 }
03261 pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
03262 }
03263
03264
03265 if (action == E_CANMATCH)
03266 aswf = asw->canmatch;
03267 else if (action == E_MATCHMORE)
03268 aswf = asw->matchmore;
03269 else
03270 aswf = asw->exists;
03271 datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
03272 if (!aswf)
03273 res = 0;
03274 else {
03275 if (chan)
03276 ast_autoservice_start(chan);
03277 res = aswf(chan, context, exten, priority, callerid, datap);
03278 if (chan)
03279 ast_autoservice_stop(chan);
03280 }
03281 if (res) {
03282 q->swo = asw;
03283 q->data = datap;
03284 q->foundcontext = context;
03285
03286 return NULL;
03287 }
03288 }
03289 q->incstack[q->stacklen++] = tmp->name;
03290
03291 for (i = tmp->includes; i; i = i->next) {
03292 if (include_valid(i)) {
03293 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
03294 #ifdef NEED_DEBUG_HERE
03295 ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
03296 #endif
03297 return e;
03298 }
03299 if (q->swo)
03300 return NULL;
03301 }
03302 }
03303 return NULL;
03304 }
03305
03306
03307
03308
03309
03310
03311 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
03312 {
03313 int parens = 0;
03314
03315 *offset = 0;
03316 *length = INT_MAX;
03317 *isfunc = 0;
03318 for (; *var; var++) {
03319 if (*var == '(') {
03320 (*isfunc)++;
03321 parens++;
03322 } else if (*var == ')') {
03323 parens--;
03324 } else if (*var == ':' && parens == 0) {
03325 *var++ = '\0';
03326 sscanf(var, "%30d:%30d", offset, length);
03327 return 1;
03328 }
03329 }
03330 return 0;
03331 }
03332
03333
03334
03335
03336
03337
03338
03339
03340
03341
03342
03343
03344 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
03345 {
03346 char *ret = workspace;
03347 int lr;
03348
03349 ast_copy_string(workspace, value, workspace_len);
03350
03351 lr = strlen(ret);
03352
03353
03354 if (offset == 0 && length >= lr)
03355 return ret;
03356
03357 if (offset < 0) {
03358 offset = lr + offset;
03359 if (offset < 0)
03360 offset = 0;
03361 }
03362
03363
03364 if (offset >= lr)
03365 return ret + lr;
03366
03367 ret += offset;
03368 if (length >= 0 && length < lr - offset)
03369 ret[length] = '\0';
03370 else if (length < 0) {
03371 if (lr > offset - length)
03372 ret[lr + length - offset] = '\0';
03373 else
03374 ret[0] = '\0';
03375 }
03376
03377 return ret;
03378 }
03379
03380 static const char *ast_str_substring(struct ast_str *value, int offset, int length)
03381 {
03382 int lr;
03383
03384 lr = ast_str_strlen(value);
03385
03386
03387 if (offset == 0 && length >= lr)
03388 return ast_str_buffer(value);
03389
03390 if (offset < 0) {
03391 offset = lr + offset;
03392 if (offset < 0)
03393 offset = 0;
03394 }
03395
03396
03397 if (offset >= lr) {
03398 ast_str_reset(value);
03399 return ast_str_buffer(value);
03400 }
03401
03402 if (offset > 0) {
03403
03404 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
03405 lr -= offset;
03406 }
03407
03408 if (length >= 0 && length < lr) {
03409 char *tmp = ast_str_buffer(value);
03410 tmp[length] = '\0';
03411 ast_str_update(value);
03412 } else if (length < 0) {
03413 if (lr > -length) {
03414 char *tmp = ast_str_buffer(value);
03415 tmp[lr + length] = '\0';
03416 ast_str_update(value);
03417 } else {
03418 ast_str_reset(value);
03419 }
03420 } else {
03421
03422 ast_str_update(value);
03423 }
03424
03425 return ast_str_buffer(value);
03426 }
03427
03428
03429
03430
03431
03432
03433
03434 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
03435 {
03436 struct ast_str *str = ast_str_create(16);
03437 const char *cret;
03438
03439 cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
03440 ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
03441 *ret = cret ? workspace : NULL;
03442 ast_free(str);
03443 }
03444
03445 const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
03446 {
03447 const char not_found = '\0';
03448 char *tmpvar;
03449 const char *ret;
03450 const char *s;
03451 int offset, length;
03452 int i, need_substring;
03453 struct varshead *places[2] = { headp, &globals };
03454 char workspace[20];
03455
03456 if (c) {
03457 ast_channel_lock(c);
03458 places[0] = &c->varshead;
03459 }
03460
03461
03462
03463
03464
03465 tmpvar = ast_strdupa(var);
03466 need_substring = parse_variable_name(tmpvar, &offset, &length, &i );
03467
03468
03469
03470
03471
03472
03473
03474
03475
03476
03477
03478
03479
03480
03481
03482
03483 s = ¬_found;
03484 if (c) {
03485
03486 if (!strncmp(var, "CALL", 4)) {
03487 if (!strncmp(var + 4, "ING", 3)) {
03488 if (!strcmp(var + 7, "PRES")) {
03489 ast_str_set(str, maxlen, "%d",
03490 ast_party_id_presentation(&c->caller.id));
03491 s = ast_str_buffer(*str);
03492 } else if (!strcmp(var + 7, "ANI2")) {
03493 ast_str_set(str, maxlen, "%d", c->caller.ani2);
03494 s = ast_str_buffer(*str);
03495 } else if (!strcmp(var + 7, "TON")) {
03496 ast_str_set(str, maxlen, "%d", c->caller.id.number.plan);
03497 s = ast_str_buffer(*str);
03498 } else if (!strcmp(var + 7, "TNS")) {
03499 ast_str_set(str, maxlen, "%d", c->dialed.transit_network_select);
03500 s = ast_str_buffer(*str);
03501 }
03502 }
03503 } else if (!strcmp(var, "HINT")) {
03504 s = ast_str_get_hint(str, maxlen, NULL, 0, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL;
03505 } else if (!strcmp(var, "HINTNAME")) {
03506 s = ast_str_get_hint(NULL, 0, str, maxlen, c, c->context, c->exten) ? ast_str_buffer(*str) : NULL;
03507 } else if (!strcmp(var, "EXTEN")) {
03508 s = c->exten;
03509 } else if (!strcmp(var, "CONTEXT")) {
03510 s = c->context;
03511 } else if (!strcmp(var, "PRIORITY")) {
03512 ast_str_set(str, maxlen, "%d", c->priority);
03513 s = ast_str_buffer(*str);
03514 } else if (!strcmp(var, "CHANNEL")) {
03515 s = c->name;
03516 } else if (!strcmp(var, "UNIQUEID")) {
03517 s = c->uniqueid;
03518 } else if (!strcmp(var, "HANGUPCAUSE")) {
03519 ast_str_set(str, maxlen, "%d", c->hangupcause);
03520 s = ast_str_buffer(*str);
03521 }
03522 }
03523 if (s == ¬_found) {
03524 if (!strcmp(var, "EPOCH")) {
03525 ast_str_set(str, maxlen, "%d", (int) time(NULL));
03526 s = ast_str_buffer(*str);
03527 } else if (!strcmp(var, "SYSTEMNAME")) {
03528 s = ast_config_AST_SYSTEM_NAME;
03529 } else if (!strcmp(var, "ENTITYID")) {
03530 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
03531 s = workspace;
03532 }
03533 }
03534
03535 for (i = 0; s == ¬_found && i < ARRAY_LEN(places); i++) {
03536 struct ast_var_t *variables;
03537 if (!places[i])
03538 continue;
03539 if (places[i] == &globals)
03540 ast_rwlock_rdlock(&globalslock);
03541 AST_LIST_TRAVERSE(places[i], variables, entries) {
03542 if (!strcasecmp(ast_var_name(variables), var)) {
03543 s = ast_var_value(variables);
03544 break;
03545 }
03546 }
03547 if (places[i] == &globals)
03548 ast_rwlock_unlock(&globalslock);
03549 }
03550 if (s == ¬_found || s == NULL) {
03551 ast_debug(5, "Result of '%s' is NULL\n", var);
03552 ret = NULL;
03553 } else {
03554 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
03555 if (s != ast_str_buffer(*str)) {
03556 ast_str_set(str, maxlen, "%s", s);
03557 }
03558 ret = ast_str_buffer(*str);
03559 if (need_substring) {
03560 ret = ast_str_substring(*str, offset, length);
03561 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
03562 }
03563 }
03564
03565 if (c) {
03566 ast_channel_unlock(c);
03567 }
03568 return ret;
03569 }
03570
03571 static void exception_store_free(void *data)
03572 {
03573 struct pbx_exception *exception = data;
03574 ast_string_field_free_memory(exception);
03575 ast_free(exception);
03576 }
03577
03578 static const struct ast_datastore_info exception_store_info = {
03579 .type = "EXCEPTION",
03580 .destroy = exception_store_free,
03581 };
03582
03583
03584
03585
03586
03587
03588
03589
03590
03591
03592
03593
03594 static int raise_exception(struct ast_channel *chan, const char *reason, int priority)
03595 {
03596 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03597 struct pbx_exception *exception = NULL;
03598
03599 if (!ds) {
03600 ds = ast_datastore_alloc(&exception_store_info, NULL);
03601 if (!ds)
03602 return -1;
03603 if (!(exception = ast_calloc_with_stringfields(1, struct pbx_exception, 128))) {
03604 ast_datastore_free(ds);
03605 return -1;
03606 }
03607 ds->data = exception;
03608 ast_channel_datastore_add(chan, ds);
03609 } else
03610 exception = ds->data;
03611
03612 ast_string_field_set(exception, reason, reason);
03613 ast_string_field_set(exception, context, chan->context);
03614 ast_string_field_set(exception, exten, chan->exten);
03615 exception->priority = chan->priority;
03616 set_ext_pri(chan, "e", priority);
03617 return 0;
03618 }
03619
03620 int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
03621 {
03622
03623 return raise_exception(chan, reason, 0);
03624 }
03625
03626 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
03627 {
03628 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03629 struct pbx_exception *exception = NULL;
03630 if (!ds || !ds->data)
03631 return -1;
03632 exception = ds->data;
03633 if (!strcasecmp(data, "REASON"))
03634 ast_copy_string(buf, exception->reason, buflen);
03635 else if (!strcasecmp(data, "CONTEXT"))
03636 ast_copy_string(buf, exception->context, buflen);
03637 else if (!strncasecmp(data, "EXTEN", 5))
03638 ast_copy_string(buf, exception->exten, buflen);
03639 else if (!strcasecmp(data, "PRIORITY"))
03640 snprintf(buf, buflen, "%d", exception->priority);
03641 else
03642 return -1;
03643 return 0;
03644 }
03645
03646 static struct ast_custom_function exception_function = {
03647 .name = "EXCEPTION",
03648 .read = acf_exception_read,
03649 };
03650
03651 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03652 {
03653 struct ast_custom_function *acf;
03654 int count_acf = 0;
03655 int like = 0;
03656
03657 switch (cmd) {
03658 case CLI_INIT:
03659 e->command = "core show functions [like]";
03660 e->usage =
03661 "Usage: core show functions [like <text>]\n"
03662 " List builtin functions, optionally only those matching a given string\n";
03663 return NULL;
03664 case CLI_GENERATE:
03665 return NULL;
03666 }
03667
03668 if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
03669 like = 1;
03670 } else if (a->argc != 3) {
03671 return CLI_SHOWUSAGE;
03672 }
03673
03674 ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
03675
03676 AST_RWLIST_RDLOCK(&acf_root);
03677 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03678 if (!like || strstr(acf->name, a->argv[4])) {
03679 count_acf++;
03680 ast_cli(a->fd, "%-20.20s %-35.35s %s\n",
03681 S_OR(acf->name, ""),
03682 S_OR(acf->syntax, ""),
03683 S_OR(acf->synopsis, ""));
03684 }
03685 }
03686 AST_RWLIST_UNLOCK(&acf_root);
03687
03688 ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
03689
03690 return CLI_SUCCESS;
03691 }
03692
03693 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03694 {
03695 struct ast_custom_function *acf;
03696
03697 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
03698 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
03699 char stxtitle[40], *syntax = NULL, *arguments = NULL;
03700 int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
03701 char *ret = NULL;
03702 int which = 0;
03703 int wordlen;
03704
03705 switch (cmd) {
03706 case CLI_INIT:
03707 e->command = "core show function";
03708 e->usage =
03709 "Usage: core show function <function>\n"
03710 " Describe a particular dialplan function.\n";
03711 return NULL;
03712 case CLI_GENERATE:
03713 wordlen = strlen(a->word);
03714
03715 AST_RWLIST_RDLOCK(&acf_root);
03716 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03717 if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
03718 ret = ast_strdup(acf->name);
03719 break;
03720 }
03721 }
03722 AST_RWLIST_UNLOCK(&acf_root);
03723
03724 return ret;
03725 }
03726
03727 if (a->argc < 4) {
03728 return CLI_SHOWUSAGE;
03729 }
03730
03731 if (!(acf = ast_custom_function_find(a->argv[3]))) {
03732 ast_cli(a->fd, "No function by that name registered.\n");
03733 return CLI_FAILURE;
03734 }
03735
03736 syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03737 if (!(syntax = ast_malloc(syntax_size))) {
03738 ast_cli(a->fd, "Memory allocation failure!\n");
03739 return CLI_FAILURE;
03740 }
03741
03742 snprintf(info, sizeof(info), "\n -= Info about function '%s' =- \n\n", acf->name);
03743 term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
03744 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03745 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03746 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
03747 term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
03748 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
03749 term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
03750 #ifdef AST_XML_DOCS
03751 if (acf->docsrc == AST_XML_DOC) {
03752 arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
03753 synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
03754 description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
03755 seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
03756 } else
03757 #endif
03758 {
03759 synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03760 synopsis = ast_malloc(synopsis_size);
03761
03762 description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03763 description = ast_malloc(description_size);
03764
03765 arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03766 arguments = ast_malloc(arguments_size);
03767
03768 seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03769 seealso = ast_malloc(seealso_size);
03770
03771
03772 if (!synopsis || !description || !arguments || !seealso) {
03773 ast_free(synopsis);
03774 ast_free(description);
03775 ast_free(arguments);
03776 ast_free(seealso);
03777 ast_free(syntax);
03778 return CLI_FAILURE;
03779 }
03780
03781 term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
03782 term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
03783 term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
03784 term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
03785 }
03786
03787 ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
03788 infotitle, syntitle, synopsis, destitle, description,
03789 stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
03790
03791 ast_free(arguments);
03792 ast_free(synopsis);
03793 ast_free(description);
03794 ast_free(seealso);
03795 ast_free(syntax);
03796
03797 return CLI_SUCCESS;
03798 }
03799
03800 struct ast_custom_function *ast_custom_function_find(const char *name)
03801 {
03802 struct ast_custom_function *acf = NULL;
03803
03804 AST_RWLIST_RDLOCK(&acf_root);
03805 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03806 if (!strcmp(name, acf->name))
03807 break;
03808 }
03809 AST_RWLIST_UNLOCK(&acf_root);
03810
03811 return acf;
03812 }
03813
03814 int ast_custom_function_unregister(struct ast_custom_function *acf)
03815 {
03816 struct ast_custom_function *cur;
03817 struct ast_custom_escalating_function *cur_escalation;
03818
03819 if (!acf) {
03820 return -1;
03821 }
03822
03823 AST_RWLIST_WRLOCK(&acf_root);
03824 if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
03825 #ifdef AST_XML_DOCS
03826 if (cur->docsrc == AST_XML_DOC) {
03827 ast_string_field_free_memory(acf);
03828 }
03829 #endif
03830 ast_verb(2, "Unregistered custom function %s\n", cur->name);
03831 }
03832 AST_RWLIST_UNLOCK(&acf_root);
03833
03834
03835 AST_RWLIST_WRLOCK(&escalation_root);
03836 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&escalation_root, cur_escalation, list) {
03837 if (cur_escalation->acf == acf) {
03838 AST_RWLIST_REMOVE_CURRENT(list);
03839 ast_free(cur_escalation);
03840 break;
03841 }
03842 }
03843 AST_RWLIST_TRAVERSE_SAFE_END;
03844 AST_RWLIST_UNLOCK(&escalation_root);
03845
03846 return cur ? 0 : -1;
03847 }
03848
03849
03850
03851
03852
03853
03854
03855
03856 static int read_escalates(const struct ast_custom_function *acf) {
03857 int res = 0;
03858 struct ast_custom_escalating_function *cur_escalation;
03859
03860 AST_RWLIST_RDLOCK(&escalation_root);
03861 AST_RWLIST_TRAVERSE(&escalation_root, cur_escalation, list) {
03862 if (cur_escalation->acf == acf) {
03863 res = cur_escalation->read_escalates;
03864 break;
03865 }
03866 }
03867 AST_RWLIST_UNLOCK(&escalation_root);
03868 return res;
03869 }
03870
03871
03872
03873
03874
03875
03876
03877
03878 static int write_escalates(const struct ast_custom_function *acf) {
03879 int res = 0;
03880 struct ast_custom_escalating_function *cur_escalation;
03881
03882 AST_RWLIST_RDLOCK(&escalation_root);
03883 AST_RWLIST_TRAVERSE(&escalation_root, cur_escalation, list) {
03884 if (cur_escalation->acf == acf) {
03885 res = cur_escalation->write_escalates;
03886 break;
03887 }
03888 }
03889 AST_RWLIST_UNLOCK(&escalation_root);
03890 return res;
03891 }
03892
03893
03894
03895
03896
03897
03898
03899
03900
03901 static int acf_retrieve_docs(struct ast_custom_function *acf)
03902 {
03903 #ifdef AST_XML_DOCS
03904 char *tmpxml;
03905
03906
03907 if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
03908 return 0;
03909 }
03910
03911 if (ast_string_field_init(acf, 128)) {
03912 return -1;
03913 }
03914
03915
03916 tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
03917 ast_string_field_set(acf, synopsis, tmpxml);
03918 ast_free(tmpxml);
03919
03920
03921 tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
03922 ast_string_field_set(acf, desc, tmpxml);
03923 ast_free(tmpxml);
03924
03925
03926 tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
03927 ast_string_field_set(acf, syntax, tmpxml);
03928 ast_free(tmpxml);
03929
03930
03931 tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
03932 ast_string_field_set(acf, arguments, tmpxml);
03933 ast_free(tmpxml);
03934
03935
03936 tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
03937 ast_string_field_set(acf, seealso, tmpxml);
03938 ast_free(tmpxml);
03939
03940 acf->docsrc = AST_XML_DOC;
03941 #endif
03942
03943 return 0;
03944 }
03945
03946 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
03947 {
03948 struct ast_custom_function *cur;
03949 char tmps[80];
03950
03951 if (!acf) {
03952 return -1;
03953 }
03954
03955 acf->mod = mod;
03956 #ifdef AST_XML_DOCS
03957 acf->docsrc = AST_STATIC_DOC;
03958 #endif
03959
03960 if (acf_retrieve_docs(acf)) {
03961 return -1;
03962 }
03963
03964 AST_RWLIST_WRLOCK(&acf_root);
03965
03966 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
03967 if (!strcmp(acf->name, cur->name)) {
03968 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
03969 AST_RWLIST_UNLOCK(&acf_root);
03970 return -1;
03971 }
03972 }
03973
03974
03975 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
03976 if (strcasecmp(acf->name, cur->name) < 0) {
03977 AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
03978 break;
03979 }
03980 }
03981 AST_RWLIST_TRAVERSE_SAFE_END;
03982
03983 if (!cur) {
03984 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
03985 }
03986
03987 AST_RWLIST_UNLOCK(&acf_root);
03988
03989 ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
03990
03991 return 0;
03992 }
03993
03994 int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod)
03995 {
03996 struct ast_custom_escalating_function *acf_escalation = NULL;
03997 int res;
03998
03999 res = __ast_custom_function_register(acf, mod);
04000 if (res != 0) {
04001 return -1;
04002 }
04003
04004 if (escalation == AST_CFE_NONE) {
04005
04006 return 0;
04007 }
04008
04009 acf_escalation = ast_calloc(1, sizeof(*acf_escalation));
04010 if (!acf_escalation) {
04011 ast_custom_function_unregister(acf);
04012 return -1;
04013 }
04014
04015 acf_escalation->acf = acf;
04016 switch (escalation) {
04017 case AST_CFE_NONE:
04018 break;
04019 case AST_CFE_READ:
04020 acf_escalation->read_escalates = 1;
04021 break;
04022 case AST_CFE_WRITE:
04023 acf_escalation->write_escalates = 1;
04024 break;
04025 case AST_CFE_BOTH:
04026 acf_escalation->read_escalates = 1;
04027 acf_escalation->write_escalates = 1;
04028 break;
04029 }
04030
04031 AST_RWLIST_WRLOCK(&escalation_root);
04032 AST_RWLIST_INSERT_TAIL(&escalation_root, acf_escalation, list);
04033 AST_RWLIST_UNLOCK(&escalation_root);
04034
04035 return 0;
04036 }
04037
04038
04039
04040
04041 static char *func_args(char *function)
04042 {
04043 char *args = strchr(function, '(');
04044
04045 if (!args) {
04046 ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
04047 } else {
04048 char *p;
04049 *args++ = '\0';
04050 if ((p = strrchr(args, ')'))) {
04051 *p = '\0';
04052 } else {
04053 ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
04054 }
04055 }
04056 return args;
04057 }
04058
04059 void pbx_live_dangerously(int new_live_dangerously)
04060 {
04061 if (new_live_dangerously && !live_dangerously) {
04062 ast_log(LOG_WARNING, "Privilege escalation protection disabled!\n"
04063 "See https://wiki.asterisk.org/wiki/x/1gKfAQ for more details.\n");
04064 }
04065
04066 if (!new_live_dangerously && live_dangerously) {
04067 ast_log(LOG_NOTICE, "Privilege escalation protection enabled.\n");
04068 }
04069 live_dangerously = new_live_dangerously;
04070 }
04071
04072 int ast_thread_inhibit_escalations(void)
04073 {
04074 int *thread_inhibit_escalations;
04075
04076 thread_inhibit_escalations = ast_threadstorage_get(
04077 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
04078
04079 if (thread_inhibit_escalations == NULL) {
04080 ast_log(LOG_ERROR, "Error inhibiting privilege escalations for current thread\n");
04081 return -1;
04082 }
04083
04084 *thread_inhibit_escalations = 1;
04085 return 0;
04086 }
04087
04088
04089
04090
04091
04092
04093
04094
04095 static int thread_inhibits_escalations(void)
04096 {
04097 int *thread_inhibit_escalations;
04098
04099 thread_inhibit_escalations = ast_threadstorage_get(
04100 &thread_inhibit_escalations_tl, sizeof(*thread_inhibit_escalations));
04101
04102 if (thread_inhibit_escalations == NULL) {
04103 ast_log(LOG_ERROR, "Error checking thread's ability to run dangerous functions\n");
04104
04105 return 1;
04106 }
04107
04108 return *thread_inhibit_escalations;
04109 }
04110
04111
04112
04113
04114
04115
04116
04117
04118
04119 static int is_read_allowed(struct ast_custom_function *acfptr)
04120 {
04121 if (!acfptr) {
04122 return 1;
04123 }
04124
04125 if (!read_escalates(acfptr)) {
04126 return 1;
04127 }
04128
04129 if (!thread_inhibits_escalations()) {
04130 return 1;
04131 }
04132
04133 if (live_dangerously) {
04134
04135 ast_debug(2, "Reading %s from a dangerous context\n",
04136 acfptr->name);
04137 return 1;
04138 }
04139
04140
04141 return 0;
04142 }
04143
04144
04145
04146
04147
04148
04149
04150
04151
04152 static int is_write_allowed(struct ast_custom_function *acfptr)
04153 {
04154 if (!acfptr) {
04155 return 1;
04156 }
04157
04158 if (!write_escalates(acfptr)) {
04159 return 1;
04160 }
04161
04162 if (!thread_inhibits_escalations()) {
04163 return 1;
04164 }
04165
04166 if (live_dangerously) {
04167
04168 ast_debug(2, "Writing %s from a dangerous context\n",
04169 acfptr->name);
04170 return 1;
04171 }
04172
04173
04174 return 0;
04175 }
04176
04177 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
04178 {
04179 char *copy = ast_strdupa(function);
04180 char *args = func_args(copy);
04181 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
04182 int res;
04183 struct ast_module_user *u = NULL;
04184
04185 if (acfptr == NULL) {
04186 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
04187 } else if (!acfptr->read && !acfptr->read2) {
04188 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
04189 } else if (!is_read_allowed(acfptr)) {
04190 ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
04191 } else if (acfptr->read) {
04192 if (acfptr->mod) {
04193 u = __ast_module_user_add(acfptr->mod, chan);
04194 }
04195 res = acfptr->read(chan, copy, args, workspace, len);
04196 if (acfptr->mod && u) {
04197 __ast_module_user_remove(acfptr->mod, u);
04198 }
04199 return res;
04200 } else {
04201 struct ast_str *str = ast_str_create(16);
04202 if (acfptr->mod) {
04203 u = __ast_module_user_add(acfptr->mod, chan);
04204 }
04205 res = acfptr->read2(chan, copy, args, &str, 0);
04206 if (acfptr->mod && u) {
04207 __ast_module_user_remove(acfptr->mod, u);
04208 }
04209 ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
04210 ast_free(str);
04211 return res;
04212 }
04213 return -1;
04214 }
04215
04216 int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
04217 {
04218 char *copy = ast_strdupa(function);
04219 char *args = func_args(copy);
04220 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
04221 int res;
04222 struct ast_module_user *u = NULL;
04223
04224 if (acfptr == NULL) {
04225 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
04226 } else if (!acfptr->read && !acfptr->read2) {
04227 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
04228 } else if (!is_read_allowed(acfptr)) {
04229 ast_log(LOG_ERROR, "Dangerous function %s read blocked\n", copy);
04230 } else {
04231 if (acfptr->mod) {
04232 u = __ast_module_user_add(acfptr->mod, chan);
04233 }
04234 ast_str_reset(*str);
04235 if (acfptr->read2) {
04236
04237 res = acfptr->read2(chan, copy, args, str, maxlen);
04238 } else {
04239
04240 int maxsize = ast_str_size(*str);
04241 if (maxlen > -1) {
04242 if (maxlen == 0) {
04243 if (acfptr->read_max) {
04244 maxsize = acfptr->read_max;
04245 } else {
04246 maxsize = VAR_BUF_SIZE;
04247 }
04248 } else {
04249 maxsize = maxlen;
04250 }
04251 ast_str_make_space(str, maxsize);
04252 }
04253 res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
04254 }
04255 if (acfptr->mod && u) {
04256 __ast_module_user_remove(acfptr->mod, u);
04257 }
04258 return res;
04259 }
04260 return -1;
04261 }
04262
04263 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
04264 {
04265 char *copy = ast_strdupa(function);
04266 char *args = func_args(copy);
04267 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
04268
04269 if (acfptr == NULL) {
04270 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
04271 } else if (!acfptr->write) {
04272 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
04273 } else if (!is_write_allowed(acfptr)) {
04274 ast_log(LOG_ERROR, "Dangerous function %s write blocked\n", copy);
04275 } else {
04276 int res;
04277 struct ast_module_user *u = NULL;
04278 if (acfptr->mod)
04279 u = __ast_module_user_add(acfptr->mod, chan);
04280 res = acfptr->write(chan, copy, args, value);
04281 if (acfptr->mod && u)
04282 __ast_module_user_remove(acfptr->mod, u);
04283 return res;
04284 }
04285
04286 return -1;
04287 }
04288
04289 void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used)
04290 {
04291
04292 char *cp4 = NULL;
04293 const char *tmp, *whereweare;
04294 int orig_size = 0;
04295 int offset, offset2, isfunction;
04296 const char *nextvar, *nextexp, *nextthing;
04297 const char *vars, *vare;
04298 char *finalvars;
04299 int pos, brackets, needsub, len;
04300 struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
04301
04302 ast_str_reset(*buf);
04303 whereweare = tmp = templ;
04304 while (!ast_strlen_zero(whereweare)) {
04305
04306 ast_str_reset(substr3);
04307
04308
04309 pos = strlen(whereweare);
04310 nextvar = NULL;
04311 nextexp = NULL;
04312 nextthing = strchr(whereweare, '$');
04313 if (nextthing) {
04314 switch (nextthing[1]) {
04315 case '{':
04316 nextvar = nextthing;
04317 pos = nextvar - whereweare;
04318 break;
04319 case '[':
04320 nextexp = nextthing;
04321 pos = nextexp - whereweare;
04322 break;
04323 default:
04324 pos = 1;
04325 }
04326 }
04327
04328 if (pos) {
04329
04330 ast_str_append_substr(buf, maxlen, whereweare, pos);
04331
04332 templ += pos;
04333 whereweare += pos;
04334 }
04335
04336 if (nextvar) {
04337
04338
04339
04340 vars = vare = nextvar + 2;
04341 brackets = 1;
04342 needsub = 0;
04343
04344
04345 while (brackets && *vare) {
04346 if ((vare[0] == '$') && (vare[1] == '{')) {
04347 needsub++;
04348 } else if (vare[0] == '{') {
04349 brackets++;
04350 } else if (vare[0] == '}') {
04351 brackets--;
04352 } else if ((vare[0] == '$') && (vare[1] == '['))
04353 needsub++;
04354 vare++;
04355 }
04356 if (brackets)
04357 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
04358 len = vare - vars - 1;
04359
04360
04361 whereweare += (len + 3);
04362
04363
04364 ast_str_set_substr(&substr1, 0, vars, len);
04365 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
04366
04367
04368 if (needsub) {
04369 size_t used;
04370 if (!substr2) {
04371 substr2 = ast_str_create(16);
04372 }
04373
04374 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
04375 finalvars = ast_str_buffer(substr2);
04376 } else {
04377 finalvars = ast_str_buffer(substr1);
04378 }
04379
04380 parse_variable_name(finalvars, &offset, &offset2, &isfunction);
04381 if (isfunction) {
04382
04383 if (c || !headp) {
04384 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
04385 } else {
04386 struct varshead old;
04387 struct ast_channel *bogus = ast_dummy_channel_alloc();
04388 if (bogus) {
04389 memcpy(&old, &bogus->varshead, sizeof(old));
04390 memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
04391 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
04392
04393 memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
04394 ast_channel_unref(bogus);
04395 } else {
04396 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
04397 }
04398 }
04399 ast_debug(2, "Function %s result is '%s'\n", finalvars, cp4 ? cp4 : "(null)");
04400 } else {
04401
04402 ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
04403 cp4 = ast_str_buffer(substr3);
04404 }
04405 if (cp4) {
04406 ast_str_substring(substr3, offset, offset2);
04407 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
04408 }
04409 } else if (nextexp) {
04410
04411
04412
04413 vars = vare = nextexp + 2;
04414 brackets = 1;
04415 needsub = 0;
04416
04417
04418 while (brackets && *vare) {
04419 if ((vare[0] == '$') && (vare[1] == '[')) {
04420 needsub++;
04421 brackets++;
04422 vare++;
04423 } else if (vare[0] == '[') {
04424 brackets++;
04425 } else if (vare[0] == ']') {
04426 brackets--;
04427 } else if ((vare[0] == '$') && (vare[1] == '{')) {
04428 needsub++;
04429 vare++;
04430 }
04431 vare++;
04432 }
04433 if (brackets)
04434 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
04435 len = vare - vars - 1;
04436
04437
04438 whereweare += (len + 3);
04439
04440
04441 ast_str_set_substr(&substr1, 0, vars, len);
04442
04443
04444 if (needsub) {
04445 size_t used;
04446 if (!substr2) {
04447 substr2 = ast_str_create(16);
04448 }
04449
04450 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
04451 finalvars = ast_str_buffer(substr2);
04452 } else {
04453 finalvars = ast_str_buffer(substr1);
04454 }
04455
04456 if (ast_str_expr(&substr3, 0, c, finalvars)) {
04457 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
04458 }
04459 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
04460 }
04461 }
04462 *used = ast_str_strlen(*buf) - orig_size;
04463 ast_free(substr1);
04464 ast_free(substr2);
04465 ast_free(substr3);
04466 }
04467
04468 void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
04469 {
04470 size_t used;
04471 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
04472 }
04473
04474 void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
04475 {
04476 size_t used;
04477 ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
04478 }
04479
04480 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
04481 {
04482
04483 char *cp4 = NULL;
04484 const char *tmp, *whereweare, *orig_cp2 = cp2;
04485 int length, offset, offset2, isfunction;
04486 char *workspace = NULL;
04487 char *ltmp = NULL, *var = NULL;
04488 char *nextvar, *nextexp, *nextthing;
04489 char *vars, *vare;
04490 int pos, brackets, needsub, len;
04491
04492 *cp2 = 0;
04493 whereweare=tmp=cp1;
04494 while (!ast_strlen_zero(whereweare) && count) {
04495
04496 pos = strlen(whereweare);
04497 nextvar = NULL;
04498 nextexp = NULL;
04499 nextthing = strchr(whereweare, '$');
04500 if (nextthing) {
04501 switch (nextthing[1]) {
04502 case '{':
04503 nextvar = nextthing;
04504 pos = nextvar - whereweare;
04505 break;
04506 case '[':
04507 nextexp = nextthing;
04508 pos = nextexp - whereweare;
04509 break;
04510 default:
04511 pos = 1;
04512 }
04513 }
04514
04515 if (pos) {
04516
04517 if (pos > count)
04518 pos = count;
04519
04520
04521 memcpy(cp2, whereweare, pos);
04522
04523 count -= pos;
04524 cp2 += pos;
04525 whereweare += pos;
04526 *cp2 = 0;
04527 }
04528
04529 if (nextvar) {
04530
04531
04532
04533 vars = vare = nextvar + 2;
04534 brackets = 1;
04535 needsub = 0;
04536
04537
04538 while (brackets && *vare) {
04539 if ((vare[0] == '$') && (vare[1] == '{')) {
04540 needsub++;
04541 } else if (vare[0] == '{') {
04542 brackets++;
04543 } else if (vare[0] == '}') {
04544 brackets--;
04545 } else if ((vare[0] == '$') && (vare[1] == '['))
04546 needsub++;
04547 vare++;
04548 }
04549 if (brackets)
04550 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
04551 len = vare - vars - 1;
04552
04553
04554 whereweare += (len + 3);
04555
04556 if (!var)
04557 var = ast_alloca(VAR_BUF_SIZE);
04558
04559
04560 ast_copy_string(var, vars, len + 1);
04561
04562
04563 if (needsub) {
04564 size_t used;
04565 if (!ltmp)
04566 ltmp = ast_alloca(VAR_BUF_SIZE);
04567
04568 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
04569 vars = ltmp;
04570 } else {
04571 vars = var;
04572 }
04573
04574 if (!workspace)
04575 workspace = ast_alloca(VAR_BUF_SIZE);
04576
04577 workspace[0] = '\0';
04578
04579 parse_variable_name(vars, &offset, &offset2, &isfunction);
04580 if (isfunction) {
04581
04582 if (c || !headp)
04583 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
04584 else {
04585 struct varshead old;
04586 struct ast_channel *c = ast_dummy_channel_alloc();
04587 if (c) {
04588 memcpy(&old, &c->varshead, sizeof(old));
04589 memcpy(&c->varshead, headp, sizeof(c->varshead));
04590 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
04591
04592 memcpy(&c->varshead, &old, sizeof(c->varshead));
04593 c = ast_channel_unref(c);
04594 } else {
04595 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
04596 }
04597 }
04598 ast_debug(2, "Function %s result is '%s'\n", vars, cp4 ? cp4 : "(null)");
04599 } else {
04600
04601 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
04602 }
04603 if (cp4) {
04604 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
04605
04606 length = strlen(cp4);
04607 if (length > count)
04608 length = count;
04609 memcpy(cp2, cp4, length);
04610 count -= length;
04611 cp2 += length;
04612 *cp2 = 0;
04613 }
04614 } else if (nextexp) {
04615
04616
04617
04618 vars = vare = nextexp + 2;
04619 brackets = 1;
04620 needsub = 0;
04621
04622
04623 while (brackets && *vare) {
04624 if ((vare[0] == '$') && (vare[1] == '[')) {
04625 needsub++;
04626 brackets++;
04627 vare++;
04628 } else if (vare[0] == '[') {
04629 brackets++;
04630 } else if (vare[0] == ']') {
04631 brackets--;
04632 } else if ((vare[0] == '$') && (vare[1] == '{')) {
04633 needsub++;
04634 vare++;
04635 }
04636 vare++;
04637 }
04638 if (brackets)
04639 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
04640 len = vare - vars - 1;
04641
04642
04643 whereweare += (len + 3);
04644
04645 if (!var)
04646 var = ast_alloca(VAR_BUF_SIZE);
04647
04648
04649 ast_copy_string(var, vars, len + 1);
04650
04651
04652 if (needsub) {
04653 size_t used;
04654 if (!ltmp)
04655 ltmp = ast_alloca(VAR_BUF_SIZE);
04656
04657 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
04658 vars = ltmp;
04659 } else {
04660 vars = var;
04661 }
04662
04663 length = ast_expr(vars, cp2, count, c);
04664
04665 if (length) {
04666 ast_debug(1, "Expression result is '%s'\n", cp2);
04667 count -= length;
04668 cp2 += length;
04669 *cp2 = 0;
04670 }
04671 }
04672 }
04673 *used = cp2 - orig_cp2;
04674 }
04675
04676 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
04677 {
04678 size_t used;
04679 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count, &used);
04680 }
04681
04682 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
04683 {
04684 size_t used;
04685 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
04686 }
04687
04688
04689
04690
04691
04692
04693
04694
04695
04696
04697
04698
04699
04700
04701
04702
04703
04704
04705
04706 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
04707 const char *context, const char *exten, int priority,
04708 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
04709 {
04710 struct ast_exten *e;
04711 struct ast_app *app;
04712 char *substitute = NULL;
04713 int res;
04714 struct pbx_find_info q = { .stacklen = 0 };
04715 char passdata[EXT_DATA_SIZE];
04716
04717 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
04718
04719 ast_rdlock_contexts();
04720 if (found)
04721 *found = 0;
04722
04723 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
04724 if (e) {
04725 if (found)
04726 *found = 1;
04727 if (matching_action) {
04728 ast_unlock_contexts();
04729 return -1;
04730 } else if (action == E_FINDLABEL) {
04731 res = e->priority;
04732 ast_unlock_contexts();
04733 return res;
04734 } else {
04735 if (!e->cached_app)
04736 e->cached_app = pbx_findapp(e->app);
04737 app = e->cached_app;
04738 if (ast_strlen_zero(e->data)) {
04739 *passdata = '\0';
04740 } else {
04741 const char *tmp;
04742 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
04743
04744 ast_copy_string(passdata, e->data, sizeof(passdata));
04745 } else {
04746
04747 substitute = ast_strdupa(e->data);
04748 }
04749 }
04750 ast_unlock_contexts();
04751 if (!app) {
04752 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
04753 return -1;
04754 }
04755 if (c->context != context)
04756 ast_copy_string(c->context, context, sizeof(c->context));
04757 if (c->exten != exten)
04758 ast_copy_string(c->exten, exten, sizeof(c->exten));
04759 c->priority = priority;
04760 if (substitute) {
04761 pbx_substitute_variables_helper(c, substitute, passdata, sizeof(passdata)-1);
04762 }
04763 #ifdef CHANNEL_TRACE
04764 ast_channel_trace_update(c);
04765 #endif
04766 ast_debug(1, "Launching '%s'\n", app->name);
04767 if (VERBOSITY_ATLEAST(3)) {
04768 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
04769 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
04770 exten, context, priority,
04771 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
04772 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
04773 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
04774 "in new stack");
04775 }
04776 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
04777 "Channel: %s\r\n"
04778 "Context: %s\r\n"
04779 "Extension: %s\r\n"
04780 "Priority: %d\r\n"
04781 "Application: %s\r\n"
04782 "AppData: %s\r\n"
04783 "Uniqueid: %s\r\n",
04784 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
04785 return pbx_exec(c, app, passdata);
04786 }
04787 } else if (q.swo) {
04788 if (found)
04789 *found = 1;
04790 ast_unlock_contexts();
04791 if (matching_action) {
04792 return -1;
04793 } else {
04794 if (!q.swo->exec) {
04795 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
04796 res = -1;
04797 }
04798 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
04799 }
04800 } else {
04801 ast_unlock_contexts();
04802
04803 switch (q.status) {
04804 case STATUS_NO_CONTEXT:
04805 if (!matching_action && !combined_find_spawn)
04806 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
04807 break;
04808 case STATUS_NO_EXTENSION:
04809 if (!matching_action && !combined_find_spawn)
04810 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
04811 break;
04812 case STATUS_NO_PRIORITY:
04813 if (!matching_action && !combined_find_spawn)
04814 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
04815 break;
04816 case STATUS_NO_LABEL:
04817 if (context && !combined_find_spawn)
04818 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
04819 break;
04820 default:
04821 ast_debug(1, "Shouldn't happen!\n");
04822 }
04823
04824 return (matching_action) ? 0 : -1;
04825 }
04826 }
04827
04828
04829 static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
04830 {
04831 struct pbx_find_info q = { .stacklen = 0 };
04832 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
04833 }
04834
04835 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
04836 {
04837 struct ast_exten *e;
04838 ast_rdlock_contexts();
04839 e = ast_hint_extension_nolock(c, context, exten);
04840 ast_unlock_contexts();
04841 return e;
04842 }
04843
04844 enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
04845 {
04846 switch (devstate) {
04847 case AST_DEVICE_ONHOLD:
04848 return AST_EXTENSION_ONHOLD;
04849 case AST_DEVICE_BUSY:
04850 return AST_EXTENSION_BUSY;
04851 case AST_DEVICE_UNKNOWN:
04852 return AST_EXTENSION_NOT_INUSE;
04853 case AST_DEVICE_UNAVAILABLE:
04854 case AST_DEVICE_INVALID:
04855 return AST_EXTENSION_UNAVAILABLE;
04856 case AST_DEVICE_RINGINUSE:
04857 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
04858 case AST_DEVICE_RINGING:
04859 return AST_EXTENSION_RINGING;
04860 case AST_DEVICE_INUSE:
04861 return AST_EXTENSION_INUSE;
04862 case AST_DEVICE_NOT_INUSE:
04863 return AST_EXTENSION_NOT_INUSE;
04864 case AST_DEVICE_TOTAL:
04865 break;
04866 }
04867
04868 return AST_EXTENSION_NOT_INUSE;
04869 }
04870
04871 static int ast_extension_state3(struct ast_str *hint_app)
04872 {
04873 char *cur;
04874 char *rest;
04875 struct ast_devstate_aggregate agg;
04876
04877
04878 rest = ast_str_buffer(hint_app);
04879
04880 ast_devstate_aggregate_init(&agg);
04881 while ((cur = strsep(&rest, "&"))) {
04882 ast_devstate_aggregate_add(&agg, ast_device_state(cur));
04883 }
04884
04885 return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
04886 }
04887
04888
04889 static int ast_extension_state2(struct ast_exten *e)
04890 {
04891 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
04892
04893 if (!e || !hint_app) {
04894 return -1;
04895 }
04896
04897 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
04898 return ast_extension_state3(hint_app);
04899 }
04900
04901
04902 const char *ast_extension_state2str(int extension_state)
04903 {
04904 int i;
04905
04906 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
04907 if (extension_states[i].extension_state == extension_state)
04908 return extension_states[i].text;
04909 }
04910 return "Unknown";
04911 }
04912
04913
04914 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
04915 {
04916 struct ast_exten *e;
04917
04918 if (!(e = ast_hint_extension(c, context, exten))) {
04919 return -1;
04920 }
04921
04922 if (e->exten[0] == '_') {
04923
04924 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
04925 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
04926 e->registrar);
04927 if (!(e = ast_hint_extension(c, context, exten))) {
04928
04929 return -1;
04930 }
04931 }
04932
04933 return ast_extension_state2(e);
04934 }
04935
04936 static int handle_statechange(void *datap)
04937 {
04938 struct ast_hint *hint;
04939 struct ast_str *hint_app;
04940 struct statechange *sc = datap;
04941 struct ao2_iterator i;
04942 struct ao2_iterator cb_iter;
04943 char context_name[AST_MAX_CONTEXT];
04944 char exten_name[AST_MAX_EXTENSION];
04945
04946 hint_app = ast_str_create(1024);
04947 if (!hint_app) {
04948 ast_free(sc);
04949 return -1;
04950 }
04951
04952 ast_mutex_lock(&context_merge_lock);
04953 i = ao2_iterator_init(hints, 0);
04954 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
04955 struct ast_state_cb *state_cb;
04956 char *cur, *parse;
04957 int state;
04958
04959 ao2_lock(hint);
04960 if (!hint->exten) {
04961
04962 ao2_unlock(hint);
04963 continue;
04964 }
04965
04966
04967 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
04968 parse = ast_str_buffer(hint_app);
04969 while ((cur = strsep(&parse, "&"))) {
04970 if (!strcasecmp(cur, sc->dev)) {
04971
04972 break;
04973 }
04974 }
04975 if (!cur) {
04976
04977 ao2_unlock(hint);
04978 continue;
04979 }
04980
04981
04982
04983
04984
04985 ast_copy_string(context_name,
04986 ast_get_context_name(ast_get_extension_context(hint->exten)),
04987 sizeof(context_name));
04988 ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
04989 sizeof(exten_name));
04990 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
04991 ao2_unlock(hint);
04992
04993
04994
04995
04996
04997
04998
04999
05000 state = ast_extension_state3(hint_app);
05001 if (state == hint->laststate) {
05002 continue;
05003 }
05004
05005
05006 hint->laststate = state;
05007
05008
05009 cb_iter = ao2_iterator_init(statecbs, 0);
05010 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
05011 state_cb->change_cb(context_name, exten_name, state, state_cb->data);
05012 }
05013 ao2_iterator_destroy(&cb_iter);
05014
05015
05016 cb_iter = ao2_iterator_init(hint->callbacks, 0);
05017 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
05018 state_cb->change_cb(context_name, exten_name, state, state_cb->data);
05019 }
05020 ao2_iterator_destroy(&cb_iter);
05021 }
05022 ao2_iterator_destroy(&i);
05023 ast_mutex_unlock(&context_merge_lock);
05024
05025 ast_free(hint_app);
05026 ast_free(sc);
05027 return 0;
05028 }
05029
05030
05031
05032
05033
05034
05035
05036
05037
05038 static void destroy_state_cb(void *doomed)
05039 {
05040 struct ast_state_cb *state_cb = doomed;
05041
05042 if (state_cb->destroy_cb) {
05043 state_cb->destroy_cb(state_cb->id, state_cb->data);
05044 }
05045 }
05046
05047
05048 int ast_extension_state_add_destroy(const char *context, const char *exten,
05049 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
05050 {
05051 struct ast_hint *hint;
05052 struct ast_state_cb *state_cb;
05053 struct ast_exten *e;
05054 int id;
05055
05056
05057 if (!context && !exten) {
05058
05059 ao2_lock(statecbs);
05060
05061
05062 ao2_find(statecbs, change_cb, OBJ_UNLINK | OBJ_NODATA);
05063
05064
05065 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
05066 ao2_unlock(statecbs);
05067 return -1;
05068 }
05069 state_cb->id = 0;
05070 state_cb->change_cb = change_cb;
05071 state_cb->destroy_cb = destroy_cb;
05072 state_cb->data = data;
05073 ao2_link(statecbs, state_cb);
05074
05075 ao2_ref(state_cb, -1);
05076 ao2_unlock(statecbs);
05077 return 0;
05078 }
05079
05080 if (!context || !exten)
05081 return -1;
05082
05083
05084 e = ast_hint_extension(NULL, context, exten);
05085 if (!e) {
05086 return -1;
05087 }
05088
05089
05090
05091
05092
05093 if (e->exten[0] == '_') {
05094 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
05095 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
05096 e->registrar);
05097 e = ast_hint_extension(NULL, context, exten);
05098 if (!e || e->exten[0] == '_') {
05099 return -1;
05100 }
05101 }
05102
05103
05104 ao2_lock(hints);
05105 hint = ao2_find(hints, e, 0);
05106 if (!hint) {
05107 ao2_unlock(hints);
05108 return -1;
05109 }
05110
05111
05112 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
05113 ao2_ref(hint, -1);
05114 ao2_unlock(hints);
05115 return -1;
05116 }
05117 do {
05118 id = stateid++;
05119
05120 } while (id == -1 || id == 0);
05121 state_cb->id = id;
05122 state_cb->change_cb = change_cb;
05123 state_cb->destroy_cb = destroy_cb;
05124 state_cb->data = data;
05125 ao2_link(hint->callbacks, state_cb);
05126
05127 ao2_ref(state_cb, -1);
05128 ao2_ref(hint, -1);
05129 ao2_unlock(hints);
05130
05131 return id;
05132 }
05133
05134
05135 int ast_extension_state_add(const char *context, const char *exten,
05136 ast_state_cb_type change_cb, void *data)
05137 {
05138 return ast_extension_state_add_destroy(context, exten, change_cb, NULL, data);
05139 }
05140
05141
05142 static int find_hint_by_cb_id(void *obj, void *arg, int flags)
05143 {
05144 struct ast_state_cb *state_cb;
05145 const struct ast_hint *hint = obj;
05146 int *id = arg;
05147
05148 if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
05149 ao2_ref(state_cb, -1);
05150 return CMP_MATCH | CMP_STOP;
05151 }
05152
05153 return 0;
05154 }
05155
05156
05157 int ast_extension_state_del(int id, ast_state_cb_type change_cb)
05158 {
05159 struct ast_state_cb *p_cur;
05160 int ret = -1;
05161
05162 if (!id) {
05163 if (!change_cb) {
05164 return ret;
05165 }
05166 p_cur = ao2_find(statecbs, change_cb, OBJ_UNLINK);
05167 if (p_cur) {
05168 ret = 0;
05169 ao2_ref(p_cur, -1);
05170 }
05171 } else {
05172 struct ast_hint *hint;
05173
05174 ao2_lock(hints);
05175 hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
05176 if (hint) {
05177 p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
05178 if (p_cur) {
05179 ret = 0;
05180 ao2_ref(p_cur, -1);
05181 }
05182 ao2_ref(hint, -1);
05183 }
05184 ao2_unlock(hints);
05185 }
05186
05187 return ret;
05188 }
05189
05190
05191 static int hint_id_cmp(void *obj, void *arg, int flags)
05192 {
05193 const struct ast_state_cb *cb = obj;
05194 int *id = arg;
05195
05196 return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
05197 }
05198
05199
05200
05201
05202
05203
05204
05205
05206
05207 static void destroy_hint(void *obj)
05208 {
05209 struct ast_hint *hint = obj;
05210
05211 if (hint->callbacks) {
05212 struct ast_state_cb *state_cb;
05213 const char *context_name;
05214 const char *exten_name;
05215
05216 if (hint->exten) {
05217 context_name = ast_get_context_name(ast_get_extension_context(hint->exten));
05218 exten_name = ast_get_extension_name(hint->exten);
05219 hint->exten = NULL;
05220 } else {
05221
05222 context_name = hint->context_name;
05223 exten_name = hint->exten_name;
05224 }
05225 while ((state_cb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
05226
05227
05228 state_cb->change_cb((char *) context_name, (char *) exten_name,
05229 AST_EXTENSION_DEACTIVATED, state_cb->data);
05230 ao2_ref(state_cb, -1);
05231 }
05232 ao2_ref(hint->callbacks, -1);
05233 }
05234 }
05235
05236
05237 static int ast_remove_hint(struct ast_exten *e)
05238 {
05239
05240 struct ast_hint *hint;
05241
05242 if (!e) {
05243 return -1;
05244 }
05245
05246 hint = ao2_find(hints, e, OBJ_UNLINK);
05247 if (!hint) {
05248 return -1;
05249 }
05250
05251
05252
05253
05254
05255 ao2_lock(hint);
05256 ast_copy_string(hint->context_name,
05257 ast_get_context_name(ast_get_extension_context(hint->exten)),
05258 sizeof(hint->context_name));
05259 ast_copy_string(hint->exten_name, ast_get_extension_name(hint->exten),
05260 sizeof(hint->exten_name));
05261 hint->exten = NULL;
05262 ao2_unlock(hint);
05263
05264 ao2_ref(hint, -1);
05265
05266 return 0;
05267 }
05268
05269
05270 static int ast_add_hint(struct ast_exten *e)
05271 {
05272 struct ast_hint *hint_new;
05273 struct ast_hint *hint_found;
05274
05275 if (!e) {
05276 return -1;
05277 }
05278
05279
05280
05281
05282
05283
05284 hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
05285 if (!hint_new) {
05286 return -1;
05287 }
05288
05289
05290 hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
05291 if (!hint_new->callbacks) {
05292 ao2_ref(hint_new, -1);
05293 return -1;
05294 }
05295 hint_new->exten = e;
05296 if (strstr(e->app, "${") && e->exten[0] == '_') {
05297 hint_new->laststate = AST_DEVICE_INVALID;
05298 } else {
05299 hint_new->laststate = ast_extension_state2(e);
05300 }
05301
05302
05303 ao2_lock(hints);
05304
05305
05306 hint_found = ao2_find(hints, e, 0);
05307 if (hint_found) {
05308 ao2_ref(hint_found, -1);
05309 ao2_unlock(hints);
05310 ao2_ref(hint_new, -1);
05311 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
05312 ast_get_extension_name(e), ast_get_extension_app(e));
05313 return -1;
05314 }
05315
05316
05317 ast_debug(2, "HINTS: Adding hint %s: %s\n",
05318 ast_get_extension_name(e), ast_get_extension_app(e));
05319 ao2_link(hints, hint_new);
05320
05321 ao2_unlock(hints);
05322 ao2_ref(hint_new, -1);
05323
05324 return 0;
05325 }
05326
05327
05328 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
05329 {
05330 struct ast_hint *hint;
05331
05332 if (!oe || !ne) {
05333 return -1;
05334 }
05335
05336 ao2_lock(hints);
05337
05338
05339
05340
05341
05342 hint = ao2_find(hints, oe, OBJ_UNLINK);
05343 if (!hint) {
05344 ao2_unlock(hints);
05345 return -1;
05346 }
05347
05348
05349 ao2_lock(hint);
05350 hint->exten = ne;
05351 ao2_unlock(hint);
05352 ao2_link(hints, hint);
05353
05354 ao2_unlock(hints);
05355 ao2_ref(hint, -1);
05356
05357 return 0;
05358 }
05359
05360
05361
05362 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
05363 {
05364 struct ast_exten *e = ast_hint_extension(c, context, exten);
05365
05366 if (e) {
05367 if (hint)
05368 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
05369 if (name) {
05370 const char *tmp = ast_get_extension_app_data(e);
05371 if (tmp)
05372 ast_copy_string(name, tmp, namesize);
05373 }
05374 return -1;
05375 }
05376 return 0;
05377 }
05378
05379
05380 int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize, struct ast_channel *c, const char *context, const char *exten)
05381 {
05382 struct ast_exten *e = ast_hint_extension(c, context, exten);
05383
05384 if (!e) {
05385 return 0;
05386 }
05387
05388 if (hint) {
05389 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
05390 }
05391 if (name) {
05392 const char *tmp = ast_get_extension_app_data(e);
05393 if (tmp) {
05394 ast_str_set(name, namesize, "%s", tmp);
05395 }
05396 }
05397 return -1;
05398 }
05399
05400 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
05401 {
05402 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
05403 }
05404
05405 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
05406 {
05407 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
05408 }
05409
05410 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
05411 {
05412 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
05413 }
05414
05415 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
05416 {
05417 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
05418 }
05419
05420 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
05421 {
05422 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
05423 }
05424
05425 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
05426 {
05427 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
05428 }
05429
05430
05431 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
05432 {
05433 ast_channel_lock(c);
05434 ast_copy_string(c->exten, exten, sizeof(c->exten));
05435 c->priority = pri;
05436 ast_channel_unlock(c);
05437 }
05438
05439
05440
05441
05442
05443
05444
05445
05446 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
05447 {
05448 int digit;
05449
05450 buf[pos] = '\0';
05451 while (ast_matchmore_extension(c, c->context, buf, 1,
05452 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05453
05454
05455 digit = ast_waitfordigit(c, waittime);
05456 if (c->_softhangup & AST_SOFTHANGUP_ASYNCGOTO) {
05457 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
05458 } else {
05459 if (!digit)
05460 break;
05461 if (digit < 0)
05462 return -1;
05463 if (pos < buflen - 1) {
05464 buf[pos++] = digit;
05465 buf[pos] = '\0';
05466 }
05467 waittime = c->pbx->dtimeoutms;
05468 }
05469 }
05470 return 0;
05471 }
05472
05473 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
05474 struct ast_pbx_args *args)
05475 {
05476 int found = 0;
05477 int res = 0;
05478 int autoloopflag;
05479 int error = 0;
05480
05481
05482 if (c->pbx) {
05483 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
05484
05485 ast_free(c->pbx);
05486 }
05487 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
05488 return -1;
05489
05490 c->pbx->rtimeoutms = 10000;
05491 c->pbx->dtimeoutms = 5000;
05492
05493 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
05494 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
05495
05496
05497 if (!ast_exists_extension(c, c->context, c->exten, c->priority,
05498 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05499
05500 ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
05501
05502
05503
05504
05505 set_ext_pri(c, "s", 1);
05506 if (!ast_exists_extension(c, c->context, c->exten, c->priority,
05507 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05508
05509 ast_verb(2, "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
05510 ast_copy_string(c->context, "default", sizeof(c->context));
05511 }
05512 }
05513 ast_channel_lock(c);
05514 if (c->cdr) {
05515
05516 ast_cdr_update(c);
05517 }
05518 ast_channel_unlock(c);
05519 for (;;) {
05520 char dst_exten[256];
05521 int pos = 0;
05522 int digit = 0;
05523 int invalid = 0;
05524 int timeout = 0;
05525
05526
05527 dst_exten[pos] = '\0';
05528
05529
05530 while (!(res = ast_spawn_extension(c, c->context, c->exten, c->priority,
05531 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL),
05532 &found, 1))) {
05533 if (!ast_check_hangup(c)) {
05534 ++c->priority;
05535 continue;
05536 }
05537
05538
05539 if (c->_softhangup & AST_SOFTHANGUP_ASYNCGOTO) {
05540 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
05541 continue;
05542 }
05543 if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT) {
05544 if (ast_exists_extension(c, c->context, "T", 1,
05545 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05546 set_ext_pri(c, "T", 1);
05547
05548 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
05549 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
05550 continue;
05551 } else if (ast_exists_extension(c, c->context, "e", 1,
05552 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05553 raise_exception(c, "ABSOLUTETIMEOUT", 1);
05554
05555 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
05556 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
05557 continue;
05558 }
05559
05560
05561 error = 1;
05562 break;
05563 }
05564 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
05565 c->exten, c->priority);
05566 error = 1;
05567 break;
05568 }
05569 if (found && res) {
05570
05571 if (strchr("0123456789ABCDEF*#", res)) {
05572 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
05573 pos = 0;
05574 dst_exten[pos++] = digit = res;
05575 dst_exten[pos] = '\0';
05576 } else if (res == AST_PBX_INCOMPLETE) {
05577 ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
05578 ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
05579
05580
05581 if (!ast_matchmore_extension(c, c->context, c->exten, 1,
05582 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05583 invalid = 1;
05584 } else {
05585 ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
05586 digit = 1;
05587 pos = strlen(dst_exten);
05588 }
05589 } else {
05590 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
05591 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
05592
05593 if ((res == AST_PBX_ERROR)
05594 && ast_exists_extension(c, c->context, "e", 1,
05595 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05596
05597 if (!strcmp(c->exten, "e")) {
05598 ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", c->context, c->exten, c->priority, c->name);
05599 error = 1;
05600 } else {
05601 raise_exception(c, "ERROR", 1);
05602 continue;
05603 }
05604 }
05605
05606 if (c->_softhangup & AST_SOFTHANGUP_ASYNCGOTO) {
05607 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
05608 continue;
05609 }
05610 if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT) {
05611 if (ast_exists_extension(c, c->context, "T", 1,
05612 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05613 set_ext_pri(c, "T", 1);
05614
05615 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
05616 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
05617 continue;
05618 } else if (ast_exists_extension(c, c->context, "e", 1,
05619 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05620 raise_exception(c, "ABSOLUTETIMEOUT", 1);
05621
05622 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
05623 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
05624 continue;
05625 }
05626
05627 }
05628 ast_channel_lock(c);
05629 if (c->cdr) {
05630 ast_cdr_update(c);
05631 }
05632 ast_channel_unlock(c);
05633 error = 1;
05634 break;
05635 }
05636 }
05637 if (error)
05638 break;
05639
05640
05641
05642
05643
05644
05645 if (invalid
05646 || (ast_strlen_zero(dst_exten) &&
05647 !ast_exists_extension(c, c->context, c->exten, 1,
05648 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL)))) {
05649
05650
05651
05652
05653
05654 if (ast_exists_extension(c, c->context, "i", 1,
05655 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05656 ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
05657 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
05658 set_ext_pri(c, "i", 1);
05659 } else if (ast_exists_extension(c, c->context, "e", 1,
05660 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05661 raise_exception(c, "INVALID", 1);
05662 } else {
05663 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
05664 c->name, c->exten, c->context);
05665 error = 1;
05666 break;
05667 }
05668 } else if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT) {
05669
05670 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
05671 } else {
05672 int waittime = 0;
05673 if (digit)
05674 waittime = c->pbx->dtimeoutms;
05675 else if (!autofallthrough)
05676 waittime = c->pbx->rtimeoutms;
05677 if (!waittime) {
05678 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
05679 if (!status)
05680 status = "UNKNOWN";
05681 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
05682 if (!strcasecmp(status, "CONGESTION"))
05683 res = pbx_builtin_congestion(c, "10");
05684 else if (!strcasecmp(status, "CHANUNAVAIL"))
05685 res = pbx_builtin_congestion(c, "10");
05686 else if (!strcasecmp(status, "BUSY"))
05687 res = pbx_builtin_busy(c, "10");
05688 error = 1;
05689 break;
05690 }
05691
05692 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
05693 break;
05694 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
05695 timeout = 1;
05696 if (!timeout
05697 && ast_exists_extension(c, c->context, dst_exten, 1,
05698 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05699 set_ext_pri(c, dst_exten, 1);
05700 } else {
05701
05702 if (!timeout && !ast_strlen_zero(dst_exten)) {
05703
05704 if (ast_exists_extension(c, c->context, "i", 1,
05705 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05706 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
05707 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
05708 set_ext_pri(c, "i", 1);
05709 } else if (ast_exists_extension(c, c->context, "e", 1,
05710 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05711 raise_exception(c, "INVALID", 1);
05712 } else {
05713 ast_log(LOG_WARNING,
05714 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
05715 dst_exten, c->context);
05716 found = 1;
05717 break;
05718 }
05719 } else {
05720
05721 if (ast_exists_extension(c, c->context, "t", 1,
05722 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05723 ast_verb(3, "Timeout on %s\n", c->name);
05724 set_ext_pri(c, "t", 1);
05725 } else if (ast_exists_extension(c, c->context, "e", 1,
05726 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05727 raise_exception(c, "RESPONSETIMEOUT", 1);
05728 } else {
05729 ast_log(LOG_WARNING,
05730 "Timeout, but no rule 't' or 'e' in context '%s'\n",
05731 c->context);
05732 found = 1;
05733 break;
05734 }
05735 }
05736 }
05737 ast_channel_lock(c);
05738 if (c->cdr) {
05739 ast_verb(2, "CDR updated on %s\n",c->name);
05740 ast_cdr_update(c);
05741 }
05742 ast_channel_unlock(c);
05743 }
05744 }
05745
05746 if (!found && !error) {
05747 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
05748 }
05749
05750 if (!args || !args->no_hangup_chan) {
05751 ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
05752 }
05753
05754 if ((!args || !args->no_hangup_chan)
05755 && !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN)
05756 && ast_exists_extension(c, c->context, "h", 1,
05757 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
05758 set_ext_pri(c, "h", 1);
05759 if (c->cdr && ast_opt_end_cdr_before_h_exten) {
05760 ast_cdr_end(c->cdr);
05761 }
05762 while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority,
05763 S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL),
05764 &found, 1)) == 0) {
05765 c->priority++;
05766 }
05767 if (found && res) {
05768
05769 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
05770 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
05771 }
05772 }
05773 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
05774 ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN);
05775 pbx_destroy(c->pbx);
05776 c->pbx = NULL;
05777
05778 if (!args || !args->no_hangup_chan) {
05779 ast_hangup(c);
05780 }
05781
05782 return 0;
05783 }
05784
05785
05786
05787
05788
05789
05790 static int increase_call_count(const struct ast_channel *c)
05791 {
05792 int failed = 0;
05793 double curloadavg;
05794 #if defined(HAVE_SYSINFO)
05795 long curfreemem;
05796 struct sysinfo sys_info;
05797 #endif
05798
05799 ast_mutex_lock(&maxcalllock);
05800 if (option_maxcalls) {
05801 if (countcalls >= option_maxcalls) {
05802 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
05803 failed = -1;
05804 }
05805 }
05806 if (option_maxload) {
05807 getloadavg(&curloadavg, 1);
05808 if (curloadavg >= option_maxload) {
05809 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
05810 failed = -1;
05811 }
05812 }
05813 #if defined(HAVE_SYSINFO)
05814 if (option_minmemfree) {
05815 if (!sysinfo(&sys_info)) {
05816
05817
05818 curfreemem = sys_info.freeram * sys_info.mem_unit;
05819 curfreemem /= 1024 * 1024;
05820 if (curfreemem < option_minmemfree) {
05821 ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
05822 failed = -1;
05823 }
05824 }
05825 }
05826 #endif
05827
05828 if (!failed) {
05829 countcalls++;
05830 totalcalls++;
05831 }
05832 ast_mutex_unlock(&maxcalllock);
05833
05834 return failed;
05835 }
05836
05837 static void decrease_call_count(void)
05838 {
05839 ast_mutex_lock(&maxcalllock);
05840 if (countcalls > 0)
05841 countcalls--;
05842 ast_mutex_unlock(&maxcalllock);
05843 }
05844
05845 static void destroy_exten(struct ast_exten *e)
05846 {
05847 if (e->priority == PRIORITY_HINT)
05848 ast_remove_hint(e);
05849
05850 if (e->peer_table)
05851 ast_hashtab_destroy(e->peer_table,0);
05852 if (e->peer_label_table)
05853 ast_hashtab_destroy(e->peer_label_table, 0);
05854 if (e->datad)
05855 e->datad(e->data);
05856 ast_free(e);
05857 }
05858
05859 static void *pbx_thread(void *data)
05860 {
05861
05862
05863
05864
05865
05866
05867
05868
05869 struct ast_channel *c = data;
05870
05871 __ast_pbx_run(c, NULL);
05872 decrease_call_count();
05873
05874 pthread_exit(NULL);
05875
05876 return NULL;
05877 }
05878
05879 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
05880 {
05881 pthread_t t;
05882
05883 if (!c) {
05884 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
05885 return AST_PBX_FAILED;
05886 }
05887
05888 if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
05889 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
05890 return AST_PBX_FAILED;
05891 }
05892
05893 if (increase_call_count(c))
05894 return AST_PBX_CALL_LIMIT;
05895
05896
05897 if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
05898 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
05899 decrease_call_count();
05900 return AST_PBX_FAILED;
05901 }
05902
05903 return AST_PBX_SUCCESS;
05904 }
05905
05906 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
05907 {
05908 enum ast_pbx_result res = AST_PBX_SUCCESS;
05909
05910 if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
05911 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
05912 return AST_PBX_FAILED;
05913 }
05914
05915 if (increase_call_count(c)) {
05916 return AST_PBX_CALL_LIMIT;
05917 }
05918
05919 res = __ast_pbx_run(c, args);
05920
05921 decrease_call_count();
05922
05923 return res;
05924 }
05925
05926 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
05927 {
05928 return ast_pbx_run_args(c, NULL);
05929 }
05930
05931 int ast_active_calls(void)
05932 {
05933 return countcalls;
05934 }
05935
05936 int ast_processed_calls(void)
05937 {
05938 return totalcalls;
05939 }
05940
05941 int pbx_set_autofallthrough(int newval)
05942 {
05943 int oldval = autofallthrough;
05944 autofallthrough = newval;
05945 return oldval;
05946 }
05947
05948 int pbx_set_extenpatternmatchnew(int newval)
05949 {
05950 int oldval = extenpatternmatchnew;
05951 extenpatternmatchnew = newval;
05952 return oldval;
05953 }
05954
05955 void pbx_set_overrideswitch(const char *newval)
05956 {
05957 if (overrideswitch) {
05958 ast_free(overrideswitch);
05959 }
05960 if (!ast_strlen_zero(newval)) {
05961 overrideswitch = ast_strdup(newval);
05962 } else {
05963 overrideswitch = NULL;
05964 }
05965 }
05966
05967
05968
05969
05970
05971 static struct ast_context *find_context(const char *context)
05972 {
05973 struct fake_context item;
05974
05975 ast_copy_string(item.name, context, sizeof(item.name));
05976
05977 return ast_hashtab_lookup(contexts_table, &item);
05978 }
05979
05980
05981
05982
05983
05984
05985 static struct ast_context *find_context_locked(const char *context)
05986 {
05987 struct ast_context *c;
05988 struct fake_context item;
05989
05990 ast_copy_string(item.name, context, sizeof(item.name));
05991
05992 ast_rdlock_contexts();
05993 c = ast_hashtab_lookup(contexts_table, &item);
05994 if (!c) {
05995 ast_unlock_contexts();
05996 }
05997
05998 return c;
05999 }
06000
06001
06002
06003
06004
06005
06006
06007 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
06008 {
06009 int ret = -1;
06010 struct ast_context *c;
06011
06012 c = find_context_locked(context);
06013 if (c) {
06014
06015 ret = ast_context_remove_include2(c, include, registrar);
06016 ast_unlock_contexts();
06017 }
06018 return ret;
06019 }
06020
06021
06022
06023
06024
06025
06026
06027
06028
06029
06030 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
06031 {
06032 struct ast_include *i, *pi = NULL;
06033 int ret = -1;
06034
06035 ast_wrlock_context(con);
06036
06037
06038 for (i = con->includes; i; pi = i, i = i->next) {
06039 if (!strcmp(i->name, include) &&
06040 (!registrar || !strcmp(i->registrar, registrar))) {
06041
06042 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
06043 if (pi)
06044 pi->next = i->next;
06045 else
06046 con->includes = i->next;
06047
06048 ast_destroy_timing(&(i->timing));
06049 ast_free(i);
06050 ret = 0;
06051 break;
06052 }
06053 }
06054
06055 ast_unlock_context(con);
06056
06057 return ret;
06058 }
06059
06060
06061
06062
06063
06064
06065 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
06066 {
06067 int ret = -1;
06068 struct ast_context *c;
06069
06070 c = find_context_locked(context);
06071 if (c) {
06072
06073 ret = ast_context_remove_switch2(c, sw, data, registrar);
06074 ast_unlock_contexts();
06075 }
06076 return ret;
06077 }
06078
06079
06080
06081
06082
06083
06084
06085
06086
06087 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
06088 {
06089 struct ast_sw *i;
06090 int ret = -1;
06091
06092 ast_wrlock_context(con);
06093
06094
06095 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
06096 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
06097 (!registrar || !strcmp(i->registrar, registrar))) {
06098
06099 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
06100 AST_LIST_REMOVE_CURRENT(list);
06101 ast_free(i);
06102 ret = 0;
06103 break;
06104 }
06105 }
06106 AST_LIST_TRAVERSE_SAFE_END;
06107
06108 ast_unlock_context(con);
06109
06110 return ret;
06111 }
06112
06113
06114 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
06115 {
06116 return ast_context_remove_extension_callerid(context, extension, priority, NULL, AST_EXT_MATCHCID_ANY, registrar);
06117 }
06118
06119 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
06120 {
06121 int ret = -1;
06122 struct ast_context *c;
06123
06124 c = find_context_locked(context);
06125 if (c) {
06126 ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid,
06127 matchcallerid, registrar, 0);
06128 ast_unlock_contexts();
06129 }
06130
06131 return ret;
06132 }
06133
06134
06135
06136
06137
06138
06139
06140
06141
06142
06143
06144 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
06145 {
06146 return ast_context_remove_extension_callerid2(con, extension, priority, NULL, AST_EXT_MATCHCID_ANY, registrar, already_locked);
06147 }
06148
06149 int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked)
06150 {
06151 struct ast_exten *exten, *prev_exten = NULL;
06152 struct ast_exten *peer;
06153 struct ast_exten ex, *exten2, *exten3;
06154 char dummy_name[1024];
06155 struct ast_exten *previous_peer = NULL;
06156 struct ast_exten *next_peer = NULL;
06157 int found = 0;
06158
06159 if (!already_locked)
06160 ast_wrlock_context(con);
06161
06162 #ifdef NEED_DEBUG
06163 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
06164 #endif
06165 #ifdef CONTEXT_DEBUG
06166 check_contexts(__FILE__, __LINE__);
06167 #endif
06168
06169 ex.exten = dummy_name;
06170 ex.matchcid = matchcallerid;
06171 ex.cidmatch = callerid;
06172 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
06173 exten = ast_hashtab_lookup(con->root_table, &ex);
06174 if (exten) {
06175 if (priority == 0) {
06176 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
06177 if (!exten2)
06178 ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
06179 if (con->pattern_tree) {
06180 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
06181
06182 if (x->exten) {
06183 x->deleted = 1;
06184 x->exten = 0;
06185 } else {
06186 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
06187 }
06188 }
06189 } else {
06190 ex.priority = priority;
06191 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
06192 if (exten2) {
06193 if (exten2->label) {
06194 exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
06195 if (!exten3)
06196 ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
06197 }
06198
06199 exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
06200 if (!exten3)
06201 ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
06202 if (exten2 == exten && exten2->peer) {
06203 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
06204 ast_hashtab_insert_immediate(con->root_table, exten2->peer);
06205 }
06206 if (ast_hashtab_size(exten->peer_table) == 0) {
06207
06208
06209 exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
06210 if (!exten3)
06211 ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
06212 if (con->pattern_tree) {
06213 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
06214 if (x->exten) {
06215 x->deleted = 1;
06216 x->exten = 0;
06217 }
06218 }
06219 }
06220 } else {
06221 ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
06222 priority, exten->exten, con->name);
06223 }
06224 }
06225 } else {
06226
06227 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
06228 extension, con->name);
06229 }
06230 #ifdef NEED_DEBUG
06231 if (con->pattern_tree) {
06232 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
06233 log_match_char_tree(con->pattern_tree, " ");
06234 }
06235 #endif
06236
06237
06238 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
06239 if (!strcmp(exten->exten, extension) &&
06240 (!registrar || !strcmp(exten->registrar, registrar)) &&
06241 (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
06242 break;
06243 }
06244 if (!exten) {
06245
06246 if (!already_locked)
06247 ast_unlock_context(con);
06248 return -1;
06249 }
06250
06251
06252 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
06253 peer && !strcmp(peer->exten, extension) &&
06254 (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, callerid))) ;
06255 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
06256
06257 if ((priority == 0 || peer->priority == priority) &&
06258 (!registrar || !strcmp(peer->registrar, registrar) )) {
06259 found = 1;
06260
06261
06262 if (!previous_peer) {
06263
06264
06265
06266
06267 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
06268 if (peer->peer) {
06269
06270
06271 peer->peer->peer_table = peer->peer_table;
06272 peer->peer->peer_label_table = peer->peer_label_table;
06273 peer->peer_table = NULL;
06274 peer->peer_label_table = NULL;
06275 }
06276 if (!prev_exten) {
06277 con->root = next_node;
06278 } else {
06279 prev_exten->next = next_node;
06280 }
06281 if (peer->peer) {
06282 peer->peer->next = peer->next;
06283 }
06284 } else {
06285 previous_peer->peer = peer->peer;
06286 }
06287
06288
06289
06290 destroy_exten(peer);
06291 } else {
06292 previous_peer = peer;
06293 }
06294 }
06295 if (!already_locked)
06296 ast_unlock_context(con);
06297 return found ? 0 : -1;
06298 }
06299
06300
06301
06302
06303
06304
06305
06306 int ast_context_lockmacro(const char *context)
06307 {
06308 struct ast_context *c;
06309 int ret = -1;
06310
06311 c = find_context_locked(context);
06312 if (c) {
06313 ast_unlock_contexts();
06314
06315
06316 ret = ast_mutex_lock(&c->macrolock);
06317 }
06318
06319 return ret;
06320 }
06321
06322
06323
06324
06325
06326
06327 int ast_context_unlockmacro(const char *context)
06328 {
06329 struct ast_context *c;
06330 int ret = -1;
06331
06332 c = find_context_locked(context);
06333 if (c) {
06334 ast_unlock_contexts();
06335
06336
06337 ret = ast_mutex_unlock(&c->macrolock);
06338 }
06339
06340 return ret;
06341 }
06342
06343
06344 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
06345 {
06346 struct ast_app *tmp, *cur = NULL;
06347 char tmps[80];
06348 int length, res;
06349 #ifdef AST_XML_DOCS
06350 char *tmpxml;
06351 #endif
06352
06353 AST_RWLIST_WRLOCK(&apps);
06354 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
06355 if (!(res = strcasecmp(app, tmp->name))) {
06356 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
06357 AST_RWLIST_UNLOCK(&apps);
06358 return -1;
06359 } else if (res < 0)
06360 break;
06361 }
06362
06363 length = sizeof(*tmp) + strlen(app) + 1;
06364
06365 if (!(tmp = ast_calloc(1, length))) {
06366 AST_RWLIST_UNLOCK(&apps);
06367 return -1;
06368 }
06369
06370 if (ast_string_field_init(tmp, 128)) {
06371 AST_RWLIST_UNLOCK(&apps);
06372 ast_free(tmp);
06373 return -1;
06374 }
06375
06376 strcpy(tmp->name, app);
06377 tmp->execute = execute;
06378 tmp->module = mod;
06379
06380 #ifdef AST_XML_DOCS
06381
06382 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
06383
06384 tmpxml = ast_xmldoc_build_synopsis("application", app, ast_module_name(tmp->module));
06385 ast_string_field_set(tmp, synopsis, tmpxml);
06386 ast_free(tmpxml);
06387
06388
06389 tmpxml = ast_xmldoc_build_description("application", app, ast_module_name(tmp->module));
06390 ast_string_field_set(tmp, description, tmpxml);
06391 ast_free(tmpxml);
06392
06393
06394 tmpxml = ast_xmldoc_build_syntax("application", app, ast_module_name(tmp->module));
06395 ast_string_field_set(tmp, syntax, tmpxml);
06396 ast_free(tmpxml);
06397
06398
06399 tmpxml = ast_xmldoc_build_arguments("application", app, ast_module_name(tmp->module));
06400 ast_string_field_set(tmp, arguments, tmpxml);
06401 ast_free(tmpxml);
06402
06403
06404 tmpxml = ast_xmldoc_build_seealso("application", app, ast_module_name(tmp->module));
06405 ast_string_field_set(tmp, seealso, tmpxml);
06406 ast_free(tmpxml);
06407 tmp->docsrc = AST_XML_DOC;
06408 } else {
06409 #endif
06410 ast_string_field_set(tmp, synopsis, synopsis);
06411 ast_string_field_set(tmp, description, description);
06412 #ifdef AST_XML_DOCS
06413 tmp->docsrc = AST_STATIC_DOC;
06414 }
06415 #endif
06416
06417
06418 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
06419 if (strcasecmp(tmp->name, cur->name) < 0) {
06420 AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
06421 break;
06422 }
06423 }
06424 AST_RWLIST_TRAVERSE_SAFE_END;
06425 if (!cur)
06426 AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
06427
06428 ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
06429
06430 AST_RWLIST_UNLOCK(&apps);
06431
06432 return 0;
06433 }
06434
06435
06436
06437
06438
06439 int ast_register_switch(struct ast_switch *sw)
06440 {
06441 struct ast_switch *tmp;
06442
06443 AST_RWLIST_WRLOCK(&switches);
06444 AST_RWLIST_TRAVERSE(&switches, tmp, list) {
06445 if (!strcasecmp(tmp->name, sw->name)) {
06446 AST_RWLIST_UNLOCK(&switches);
06447 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
06448 return -1;
06449 }
06450 }
06451 AST_RWLIST_INSERT_TAIL(&switches, sw, list);
06452 AST_RWLIST_UNLOCK(&switches);
06453
06454 return 0;
06455 }
06456
06457 void ast_unregister_switch(struct ast_switch *sw)
06458 {
06459 AST_RWLIST_WRLOCK(&switches);
06460 AST_RWLIST_REMOVE(&switches, sw, list);
06461 AST_RWLIST_UNLOCK(&switches);
06462 }
06463
06464
06465
06466
06467
06468 static void print_app_docs(struct ast_app *aa, int fd)
06469 {
06470
06471 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40];
06472 char seealsotitle[40];
06473 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL;
06474 char *seealso = NULL;
06475 int syntax_size, synopsis_size, description_size, arguments_size, seealso_size;
06476
06477 snprintf(info, sizeof(info), "\n -= Info about application '%s' =- \n\n", aa->name);
06478 term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
06479
06480 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
06481 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
06482 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
06483 term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
06484 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
06485
06486 #ifdef AST_XML_DOCS
06487 if (aa->docsrc == AST_XML_DOC) {
06488 description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
06489 arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
06490 synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
06491 seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
06492
06493 if (!synopsis || !description || !arguments || !seealso) {
06494 goto return_cleanup;
06495 }
06496 } else
06497 #endif
06498 {
06499 synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
06500 synopsis = ast_malloc(synopsis_size);
06501
06502 description_size = strlen(S_OR(aa->description, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
06503 description = ast_malloc(description_size);
06504
06505 arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
06506 arguments = ast_malloc(arguments_size);
06507
06508 seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
06509 seealso = ast_malloc(seealso_size);
06510
06511 if (!synopsis || !description || !arguments || !seealso) {
06512 goto return_cleanup;
06513 }
06514
06515 term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
06516 term_color(description, S_OR(aa->description, "Not available"), COLOR_CYAN, 0, description_size);
06517 term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
06518 term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
06519 }
06520
06521
06522 syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
06523 if (!(syntax = ast_malloc(syntax_size))) {
06524 goto return_cleanup;
06525 }
06526 term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
06527
06528 ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
06529 infotitle, syntitle, synopsis, destitle, description,
06530 stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
06531
06532 return_cleanup:
06533 ast_free(description);
06534 ast_free(arguments);
06535 ast_free(synopsis);
06536 ast_free(seealso);
06537 ast_free(syntax);
06538 }
06539
06540
06541
06542
06543 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06544 {
06545 struct ast_app *aa;
06546 int app, no_registered_app = 1;
06547
06548 switch (cmd) {
06549 case CLI_INIT:
06550 e->command = "core show application";
06551 e->usage =
06552 "Usage: core show application <application> [<application> [<application> [...]]]\n"
06553 " Describes a particular application.\n";
06554 return NULL;
06555 case CLI_GENERATE:
06556
06557
06558
06559
06560
06561 return ast_complete_applications(a->line, a->word, a->n);
06562 }
06563
06564 if (a->argc < 4) {
06565 return CLI_SHOWUSAGE;
06566 }
06567
06568 AST_RWLIST_RDLOCK(&apps);
06569 AST_RWLIST_TRAVERSE(&apps, aa, list) {
06570
06571 for (app = 3; app < a->argc; app++) {
06572 if (strcasecmp(aa->name, a->argv[app])) {
06573 continue;
06574 }
06575
06576
06577 no_registered_app = 0;
06578
06579 print_app_docs(aa, a->fd);
06580 }
06581 }
06582 AST_RWLIST_UNLOCK(&apps);
06583
06584
06585 if (no_registered_app) {
06586 ast_cli(a->fd, "Your application(s) is (are) not registered\n");
06587 return CLI_FAILURE;
06588 }
06589
06590 return CLI_SUCCESS;
06591 }
06592
06593
06594 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06595 {
06596 struct ast_hint *hint;
06597 int num = 0;
06598 int watchers;
06599 struct ao2_iterator i;
06600
06601 switch (cmd) {
06602 case CLI_INIT:
06603 e->command = "core show hints";
06604 e->usage =
06605 "Usage: core show hints\n"
06606 " List registered hints.\n"
06607 " Hint details are shown in four columns. In order from left to right, they are:\n"
06608 " 1. Hint extension URI.\n"
06609 " 2. Mapped device state identifiers.\n"
06610 " 3. Current extension state. The aggregate of mapped device states.\n"
06611 " 4. Watchers - number of subscriptions and other entities watching this hint.\n";
06612 return NULL;
06613 case CLI_GENERATE:
06614 return NULL;
06615 }
06616
06617 if (ao2_container_count(hints) == 0) {
06618 ast_cli(a->fd, "There are no registered dialplan hints\n");
06619 return CLI_SUCCESS;
06620 }
06621
06622 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
06623
06624 i = ao2_iterator_init(hints, 0);
06625 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
06626 ao2_lock(hint);
06627 if (!hint->exten) {
06628
06629 ao2_unlock(hint);
06630 continue;
06631 }
06632 watchers = ao2_container_count(hint->callbacks);
06633 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
06634 ast_get_extension_name(hint->exten),
06635 ast_get_context_name(ast_get_extension_context(hint->exten)),
06636 ast_get_extension_app(hint->exten),
06637 ast_extension_state2str(hint->laststate), watchers);
06638 ao2_unlock(hint);
06639 num++;
06640 }
06641 ao2_iterator_destroy(&i);
06642
06643 ast_cli(a->fd, "----------------\n");
06644 ast_cli(a->fd, "- %d hints registered\n", num);
06645 return CLI_SUCCESS;
06646 }
06647
06648
06649 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
06650 {
06651 struct ast_hint *hint;
06652 char *ret = NULL;
06653 int which = 0;
06654 int wordlen;
06655 struct ao2_iterator i;
06656
06657 if (pos != 3)
06658 return NULL;
06659
06660 wordlen = strlen(word);
06661
06662
06663 i = ao2_iterator_init(hints, 0);
06664 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
06665 ao2_lock(hint);
06666 if (!hint->exten) {
06667
06668 ao2_unlock(hint);
06669 continue;
06670 }
06671 if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
06672 ret = ast_strdup(ast_get_extension_name(hint->exten));
06673 ao2_unlock(hint);
06674 ao2_ref(hint, -1);
06675 break;
06676 }
06677 ao2_unlock(hint);
06678 }
06679 ao2_iterator_destroy(&i);
06680
06681 return ret;
06682 }
06683
06684
06685 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06686 {
06687 struct ast_hint *hint;
06688 int watchers;
06689 int num = 0, extenlen;
06690 struct ao2_iterator i;
06691
06692 switch (cmd) {
06693 case CLI_INIT:
06694 e->command = "core show hint";
06695 e->usage =
06696 "Usage: core show hint <exten>\n"
06697 " List registered hint.\n"
06698 " Hint details are shown in four columns. In order from left to right, they are:\n"
06699 " 1. Hint extension URI.\n"
06700 " 2. Mapped device state identifiers.\n"
06701 " 3. Current extension state. The aggregate of mapped device states.\n"
06702 " 4. Watchers - number of subscriptions and other entities watching this hint.\n";
06703
06704 return NULL;
06705 case CLI_GENERATE:
06706 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
06707 }
06708
06709 if (a->argc < 4)
06710 return CLI_SHOWUSAGE;
06711
06712 if (ao2_container_count(hints) == 0) {
06713 ast_cli(a->fd, "There are no registered dialplan hints\n");
06714 return CLI_SUCCESS;
06715 }
06716
06717 extenlen = strlen(a->argv[3]);
06718 i = ao2_iterator_init(hints, 0);
06719 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
06720 ao2_lock(hint);
06721 if (!hint->exten) {
06722
06723 ao2_unlock(hint);
06724 continue;
06725 }
06726 if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
06727 watchers = ao2_container_count(hint->callbacks);
06728 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
06729 ast_get_extension_name(hint->exten),
06730 ast_get_context_name(ast_get_extension_context(hint->exten)),
06731 ast_get_extension_app(hint->exten),
06732 ast_extension_state2str(hint->laststate), watchers);
06733 num++;
06734 }
06735 ao2_unlock(hint);
06736 }
06737 ao2_iterator_destroy(&i);
06738 if (!num)
06739 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
06740 else
06741 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
06742 return CLI_SUCCESS;
06743 }
06744
06745
06746
06747 static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06748 {
06749 struct ast_switch *sw;
06750
06751 switch (cmd) {
06752 case CLI_INIT:
06753 e->command = "core show switches";
06754 e->usage =
06755 "Usage: core show switches\n"
06756 " List registered switches\n";
06757 return NULL;
06758 case CLI_GENERATE:
06759 return NULL;
06760 }
06761
06762 AST_RWLIST_RDLOCK(&switches);
06763
06764 if (AST_RWLIST_EMPTY(&switches)) {
06765 AST_RWLIST_UNLOCK(&switches);
06766 ast_cli(a->fd, "There are no registered alternative switches\n");
06767 return CLI_SUCCESS;
06768 }
06769
06770 ast_cli(a->fd, "\n -= Registered Asterisk Alternative Switches =-\n");
06771 AST_RWLIST_TRAVERSE(&switches, sw, list)
06772 ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
06773
06774 AST_RWLIST_UNLOCK(&switches);
06775
06776 return CLI_SUCCESS;
06777 }
06778
06779 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06780 {
06781 struct ast_app *aa;
06782 int like = 0, describing = 0;
06783 int total_match = 0;
06784 int total_apps = 0;
06785 static const char * const choices[] = { "like", "describing", NULL };
06786
06787 switch (cmd) {
06788 case CLI_INIT:
06789 e->command = "core show applications [like|describing]";
06790 e->usage =
06791 "Usage: core show applications [{like|describing} <text>]\n"
06792 " List applications which are currently available.\n"
06793 " If 'like', <text> will be a substring of the app name\n"
06794 " If 'describing', <text> will be a substring of the description\n";
06795 return NULL;
06796 case CLI_GENERATE:
06797 return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
06798 }
06799
06800 AST_RWLIST_RDLOCK(&apps);
06801
06802 if (AST_RWLIST_EMPTY(&apps)) {
06803 ast_cli(a->fd, "There are no registered applications\n");
06804 AST_RWLIST_UNLOCK(&apps);
06805 return CLI_SUCCESS;
06806 }
06807
06808
06809 if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
06810 like = 1;
06811 } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
06812 describing = 1;
06813 }
06814
06815
06816 if ((!like) && (!describing)) {
06817 ast_cli(a->fd, " -= Registered Asterisk Applications =-\n");
06818 } else {
06819 ast_cli(a->fd, " -= Matching Asterisk Applications =-\n");
06820 }
06821
06822 AST_RWLIST_TRAVERSE(&apps, aa, list) {
06823 int printapp = 0;
06824 total_apps++;
06825 if (like) {
06826 if (strcasestr(aa->name, a->argv[4])) {
06827 printapp = 1;
06828 total_match++;
06829 }
06830 } else if (describing) {
06831 if (aa->description) {
06832
06833 int i;
06834 printapp = 1;
06835 for (i = 4; i < a->argc; i++) {
06836 if (!strcasestr(aa->description, a->argv[i])) {
06837 printapp = 0;
06838 } else {
06839 total_match++;
06840 }
06841 }
06842 }
06843 } else {
06844 printapp = 1;
06845 }
06846
06847 if (printapp) {
06848 ast_cli(a->fd," %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
06849 }
06850 }
06851 if ((!like) && (!describing)) {
06852 ast_cli(a->fd, " -= %d Applications Registered =-\n",total_apps);
06853 } else {
06854 ast_cli(a->fd, " -= %d Applications Matching =-\n",total_match);
06855 }
06856
06857 AST_RWLIST_UNLOCK(&apps);
06858
06859 return CLI_SUCCESS;
06860 }
06861
06862
06863
06864
06865 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
06866 int state)
06867 {
06868 struct ast_context *c = NULL;
06869 char *ret = NULL;
06870 int which = 0;
06871 int wordlen;
06872
06873
06874 if (pos != 2)
06875 return NULL;
06876
06877 ast_rdlock_contexts();
06878
06879 wordlen = strlen(word);
06880
06881
06882 while ( (c = ast_walk_contexts(c)) ) {
06883 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
06884 ret = ast_strdup(ast_get_context_name(c));
06885 break;
06886 }
06887 }
06888
06889 ast_unlock_contexts();
06890
06891 return ret;
06892 }
06893
06894
06895 struct dialplan_counters {
06896 int total_items;
06897 int total_context;
06898 int total_exten;
06899 int total_prio;
06900 int context_existence;
06901 int extension_existence;
06902 };
06903
06904
06905 static void print_ext(struct ast_exten *e, char * buf, int buflen)
06906 {
06907 int prio = ast_get_extension_priority(e);
06908 if (prio == PRIORITY_HINT) {
06909 snprintf(buf, buflen, "hint: %s",
06910 ast_get_extension_app(e));
06911 } else {
06912 snprintf(buf, buflen, "%d. %s(%s)",
06913 prio, ast_get_extension_app(e),
06914 (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
06915 }
06916 }
06917
06918
06919 static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
06920 {
06921 struct ast_context *c = NULL;
06922 int res = 0, old_total_exten = dpc->total_exten;
06923
06924 ast_rdlock_contexts();
06925
06926
06927 while ( (c = ast_walk_contexts(c)) ) {
06928 struct ast_exten *e;
06929 struct ast_include *i;
06930 struct ast_ignorepat *ip;
06931 #ifndef LOW_MEMORY
06932 char buf[1024], buf2[1024];
06933 #else
06934 char buf[256], buf2[256];
06935 #endif
06936 int context_info_printed = 0;
06937
06938 if (context && strcmp(ast_get_context_name(c), context))
06939 continue;
06940
06941 dpc->context_existence = 1;
06942
06943 ast_rdlock_context(c);
06944
06945
06946
06947
06948
06949
06950
06951 if (!exten) {
06952 dpc->total_context++;
06953 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
06954 ast_get_context_name(c), ast_get_context_registrar(c));
06955 context_info_printed = 1;
06956 }
06957
06958
06959 e = NULL;
06960 while ( (e = ast_walk_context_extensions(c, e)) ) {
06961 struct ast_exten *p;
06962
06963 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
06964 continue;
06965
06966 dpc->extension_existence = 1;
06967
06968
06969 if (!context_info_printed) {
06970 dpc->total_context++;
06971 if (rinclude) {
06972 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
06973 ast_get_context_name(c), ast_get_context_registrar(c));
06974 } else {
06975 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
06976 ast_get_context_name(c), ast_get_context_registrar(c));
06977 }
06978 context_info_printed = 1;
06979 }
06980 dpc->total_prio++;
06981
06982
06983 if (e->matchcid == AST_EXT_MATCHCID_ON)
06984 snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
06985 else
06986 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
06987
06988 print_ext(e, buf2, sizeof(buf2));
06989
06990 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
06991 ast_get_extension_registrar(e));
06992
06993 dpc->total_exten++;
06994
06995 p = e;
06996 while ( (p = ast_walk_extension_priorities(e, p)) ) {
06997 const char *el = ast_get_extension_label(p);
06998 dpc->total_prio++;
06999 if (el)
07000 snprintf(buf, sizeof(buf), " [%s]", el);
07001 else
07002 buf[0] = '\0';
07003 print_ext(p, buf2, sizeof(buf2));
07004
07005 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
07006 ast_get_extension_registrar(p));
07007 }
07008 }
07009
07010
07011 i = NULL;
07012 while ( (i = ast_walk_context_includes(c, i)) ) {
07013 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
07014 if (exten) {
07015
07016 if (includecount >= AST_PBX_MAX_STACK) {
07017 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
07018 } else {
07019 int dupe = 0;
07020 int x;
07021 for (x = 0; x < includecount; x++) {
07022 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
07023 dupe++;
07024 break;
07025 }
07026 }
07027 if (!dupe) {
07028 includes[includecount] = ast_get_include_name(i);
07029 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
07030 } else {
07031 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
07032 }
07033 }
07034 } else {
07035 ast_cli(fd, " Include => %-45s [%s]\n",
07036 buf, ast_get_include_registrar(i));
07037 }
07038 }
07039
07040
07041 ip = NULL;
07042 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
07043 const char *ipname = ast_get_ignorepat_name(ip);
07044 char ignorepat[AST_MAX_EXTENSION];
07045 snprintf(buf, sizeof(buf), "'%s'", ipname);
07046 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
07047 if (!exten || ast_extension_match(ignorepat, exten)) {
07048 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
07049 buf, ast_get_ignorepat_registrar(ip));
07050 }
07051 }
07052 if (!rinclude) {
07053 struct ast_sw *sw = NULL;
07054 while ( (sw = ast_walk_context_switches(c, sw)) ) {
07055 snprintf(buf, sizeof(buf), "'%s/%s'",
07056 ast_get_switch_name(sw),
07057 ast_get_switch_data(sw));
07058 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
07059 buf, ast_get_switch_registrar(sw));
07060 }
07061 }
07062
07063 ast_unlock_context(c);
07064
07065
07066 if (context_info_printed)
07067 ast_cli(fd, "\n");
07068 }
07069 ast_unlock_contexts();
07070
07071 return (dpc->total_exten == old_total_exten) ? -1 : res;
07072 }
07073
07074 static int show_debug_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
07075 {
07076 struct ast_context *c = NULL;
07077 int res = 0, old_total_exten = dpc->total_exten;
07078
07079 ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
07080
07081 ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
07082 ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
07083 ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
07084 ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
07085 ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
07086 ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
07087 ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
07088 ast_rdlock_contexts();
07089
07090
07091 while ( (c = ast_walk_contexts(c)) ) {
07092 int context_info_printed = 0;
07093
07094 if (context && strcmp(ast_get_context_name(c), context))
07095 continue;
07096
07097 dpc->context_existence = 1;
07098
07099 if (!c->pattern_tree) {
07100
07101 ast_exists_extension(NULL, c->name, "s", 1, "");
07102 }
07103
07104 ast_rdlock_context(c);
07105
07106 dpc->total_context++;
07107 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
07108 ast_get_context_name(c), ast_get_context_registrar(c));
07109 context_info_printed = 1;
07110
07111 if (c->pattern_tree)
07112 {
07113 cli_match_char_tree(c->pattern_tree, " ", fd);
07114 } else {
07115 ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
07116 }
07117
07118 ast_unlock_context(c);
07119
07120
07121 if (context_info_printed)
07122 ast_cli(fd, "\n");
07123 }
07124 ast_unlock_contexts();
07125
07126 return (dpc->total_exten == old_total_exten) ? -1 : res;
07127 }
07128
07129 static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07130 {
07131 char *exten = NULL, *context = NULL;
07132
07133 struct dialplan_counters counters;
07134 const char *incstack[AST_PBX_MAX_STACK];
07135
07136 switch (cmd) {
07137 case CLI_INIT:
07138 e->command = "dialplan show";
07139 e->usage =
07140 "Usage: dialplan show [[exten@]context]\n"
07141 " Show dialplan\n";
07142 return NULL;
07143 case CLI_GENERATE:
07144 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
07145 }
07146
07147 memset(&counters, 0, sizeof(counters));
07148
07149 if (a->argc != 2 && a->argc != 3)
07150 return CLI_SHOWUSAGE;
07151
07152
07153 if (a->argc == 3) {
07154 if (strchr(a->argv[2], '@')) {
07155 context = ast_strdupa(a->argv[2]);
07156 exten = strsep(&context, "@");
07157
07158 if (ast_strlen_zero(exten))
07159 exten = NULL;
07160 } else {
07161 context = ast_strdupa(a->argv[2]);
07162 }
07163 if (ast_strlen_zero(context))
07164 context = NULL;
07165 }
07166
07167 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
07168
07169
07170 if (context && !counters.context_existence) {
07171 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
07172 return CLI_FAILURE;
07173 }
07174
07175 if (exten && !counters.extension_existence) {
07176 if (context)
07177 ast_cli(a->fd, "There is no existence of %s@%s extension\n",
07178 exten, context);
07179 else
07180 ast_cli(a->fd,
07181 "There is no existence of '%s' extension in all contexts\n",
07182 exten);
07183 return CLI_FAILURE;
07184 }
07185
07186 ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
07187 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
07188 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
07189 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
07190
07191
07192 return CLI_SUCCESS;
07193 }
07194
07195
07196 static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07197 {
07198 char *exten = NULL, *context = NULL;
07199
07200 struct dialplan_counters counters;
07201 const char *incstack[AST_PBX_MAX_STACK];
07202
07203 switch (cmd) {
07204 case CLI_INIT:
07205 e->command = "dialplan debug";
07206 e->usage =
07207 "Usage: dialplan debug [context]\n"
07208 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
07209 return NULL;
07210 case CLI_GENERATE:
07211 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
07212 }
07213
07214 memset(&counters, 0, sizeof(counters));
07215
07216 if (a->argc != 2 && a->argc != 3)
07217 return CLI_SHOWUSAGE;
07218
07219
07220
07221 if (a->argc == 3) {
07222 if (strchr(a->argv[2], '@')) {
07223 context = ast_strdupa(a->argv[2]);
07224 exten = strsep(&context, "@");
07225
07226 if (ast_strlen_zero(exten))
07227 exten = NULL;
07228 } else {
07229 context = ast_strdupa(a->argv[2]);
07230 }
07231 if (ast_strlen_zero(context))
07232 context = NULL;
07233 }
07234
07235 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
07236
07237
07238 if (context && !counters.context_existence) {
07239 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
07240 return CLI_FAILURE;
07241 }
07242
07243
07244 ast_cli(a->fd,"-= %d %s. =-\n",
07245 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
07246
07247
07248 return CLI_SUCCESS;
07249 }
07250
07251
07252 static void manager_dpsendack(struct mansession *s, const struct message *m)
07253 {
07254 astman_send_listack(s, m, "DialPlan list will follow", "start");
07255 }
07256
07257
07258
07259
07260
07261 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
07262 const char *actionidtext, const char *context,
07263 const char *exten, struct dialplan_counters *dpc,
07264 struct ast_include *rinclude)
07265 {
07266 struct ast_context *c;
07267 int res = 0, old_total_exten = dpc->total_exten;
07268
07269 if (ast_strlen_zero(exten))
07270 exten = NULL;
07271 if (ast_strlen_zero(context))
07272 context = NULL;
07273
07274 ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
07275
07276
07277 if (ast_rdlock_contexts()) {
07278 astman_send_error(s, m, "Failed to lock contexts");
07279 ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
07280 return -1;
07281 }
07282
07283 c = NULL;
07284 while ( (c = ast_walk_contexts(c)) ) {
07285 struct ast_exten *e;
07286 struct ast_include *i;
07287 struct ast_ignorepat *ip;
07288
07289 if (context && strcmp(ast_get_context_name(c), context) != 0)
07290 continue;
07291
07292 dpc->context_existence = 1;
07293 dpc->total_context++;
07294
07295 ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
07296
07297 if (ast_rdlock_context(c)) {
07298 ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
07299 continue;
07300 }
07301
07302
07303 e = NULL;
07304 while ( (e = ast_walk_context_extensions(c, e)) ) {
07305 struct ast_exten *p;
07306
07307
07308 if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
07309
07310 ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
07311 continue;
07312 }
07313 ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
07314
07315 dpc->extension_existence = 1;
07316
07317 dpc->total_exten++;
07318
07319 p = NULL;
07320 while ( (p = ast_walk_extension_priorities(e, p)) ) {
07321 int prio = ast_get_extension_priority(p);
07322
07323 dpc->total_prio++;
07324 if (!dpc->total_items++)
07325 manager_dpsendack(s, m);
07326 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
07327 astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
07328
07329
07330 if (ast_get_extension_label(p))
07331 astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
07332
07333 if (prio == PRIORITY_HINT) {
07334 astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
07335 } else {
07336 astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
07337 }
07338 astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
07339 }
07340 }
07341
07342 i = NULL;
07343 while ( (i = ast_walk_context_includes(c, i)) ) {
07344 if (exten) {
07345
07346 manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
07347 } else {
07348 if (!dpc->total_items++)
07349 manager_dpsendack(s, m);
07350 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
07351 astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
07352 astman_append(s, "\r\n");
07353 ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
07354 }
07355 }
07356
07357 ip = NULL;
07358 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
07359 const char *ipname = ast_get_ignorepat_name(ip);
07360 char ignorepat[AST_MAX_EXTENSION];
07361
07362 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
07363 if (!exten || ast_extension_match(ignorepat, exten)) {
07364 if (!dpc->total_items++)
07365 manager_dpsendack(s, m);
07366 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
07367 astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
07368 astman_append(s, "\r\n");
07369 }
07370 }
07371 if (!rinclude) {
07372 struct ast_sw *sw = NULL;
07373 while ( (sw = ast_walk_context_switches(c, sw)) ) {
07374 if (!dpc->total_items++)
07375 manager_dpsendack(s, m);
07376 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
07377 astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw));
07378 astman_append(s, "\r\n");
07379 ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
07380 }
07381 }
07382
07383 ast_unlock_context(c);
07384 }
07385 ast_unlock_contexts();
07386
07387 if (dpc->total_exten == old_total_exten) {
07388 ast_debug(3, "manager_show_dialplan: Found nothing new\n");
07389
07390 return -1;
07391 } else {
07392 return res;
07393 }
07394 }
07395
07396
07397 static int manager_show_dialplan(struct mansession *s, const struct message *m)
07398 {
07399 const char *exten, *context;
07400 const char *id = astman_get_header(m, "ActionID");
07401 char idtext[256];
07402
07403
07404 struct dialplan_counters counters;
07405
07406 if (!ast_strlen_zero(id))
07407 snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
07408 else
07409 idtext[0] = '\0';
07410
07411 memset(&counters, 0, sizeof(counters));
07412
07413 exten = astman_get_header(m, "Extension");
07414 context = astman_get_header(m, "Context");
07415
07416 manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
07417
07418 if (!ast_strlen_zero(context) && !counters.context_existence) {
07419 char errorbuf[BUFSIZ];
07420
07421 snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
07422 astman_send_error(s, m, errorbuf);
07423 return 0;
07424 }
07425 if (!ast_strlen_zero(exten) && !counters.extension_existence) {
07426 char errorbuf[BUFSIZ];
07427
07428 if (!ast_strlen_zero(context))
07429 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
07430 else
07431 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
07432 astman_send_error(s, m, errorbuf);
07433 return 0;
07434 }
07435
07436 if (!counters.total_items) {
07437 manager_dpsendack(s, m);
07438 }
07439
07440 astman_append(s, "Event: ShowDialPlanComplete\r\n"
07441 "EventList: Complete\r\n"
07442 "ListItems: %d\r\n"
07443 "ListExtensions: %d\r\n"
07444 "ListPriorities: %d\r\n"
07445 "ListContexts: %d\r\n"
07446 "%s"
07447 "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
07448
07449
07450 return 0;
07451 }
07452
07453
07454 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07455 {
07456 int i = 0;
07457 struct ast_var_t *newvariable;
07458
07459 switch (cmd) {
07460 case CLI_INIT:
07461 e->command = "dialplan show globals";
07462 e->usage =
07463 "Usage: dialplan show globals\n"
07464 " List current global dialplan variables and their values\n";
07465 return NULL;
07466 case CLI_GENERATE:
07467 return NULL;
07468 }
07469
07470 ast_rwlock_rdlock(&globalslock);
07471 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
07472 i++;
07473 ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
07474 }
07475 ast_rwlock_unlock(&globalslock);
07476 ast_cli(a->fd, "\n -- %d variable(s)\n", i);
07477
07478 return CLI_SUCCESS;
07479 }
07480
07481 #ifdef AST_DEVMODE
07482 static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07483 {
07484 struct ast_devstate_aggregate agg;
07485 int i, j, exten, combined;
07486
07487 switch (cmd) {
07488 case CLI_INIT:
07489 e->command = "core show device2extenstate";
07490 e->usage =
07491 "Usage: core show device2extenstate\n"
07492 " Lists device state to extension state combinations.\n";
07493 case CLI_GENERATE:
07494 return NULL;
07495 }
07496 for (i = 0; i < AST_DEVICE_TOTAL; i++) {
07497 for (j = 0; j < AST_DEVICE_TOTAL; j++) {
07498 ast_devstate_aggregate_init(&agg);
07499 ast_devstate_aggregate_add(&agg, i);
07500 ast_devstate_aggregate_add(&agg, j);
07501 combined = ast_devstate_aggregate_result(&agg);
07502 exten = ast_devstate_to_extenstate(combined);
07503 ast_cli(a->fd, "\n Exten:%14s CombinedDevice:%12s Dev1:%12s Dev2:%12s", ast_extension_state2str(exten), ast_devstate_str(combined), ast_devstate_str(j), ast_devstate_str(i));
07504 }
07505 }
07506 ast_cli(a->fd, "\n");
07507 return CLI_SUCCESS;
07508 }
07509 #endif
07510
07511
07512 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07513 {
07514 struct ast_channel *chan = NULL;
07515 struct ast_str *vars = ast_str_alloca(BUFSIZ * 4);
07516
07517 switch (cmd) {
07518 case CLI_INIT:
07519 e->command = "dialplan show chanvar";
07520 e->usage =
07521 "Usage: dialplan show chanvar <channel>\n"
07522 " List current channel variables and their values\n";
07523 return NULL;
07524 case CLI_GENERATE:
07525 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
07526 }
07527
07528 if (a->argc != e->args + 1)
07529 return CLI_SHOWUSAGE;
07530
07531 if (!(chan = ast_channel_get_by_name(a->argv[e->args]))) {
07532 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
07533 return CLI_FAILURE;
07534 }
07535
07536 pbx_builtin_serialize_variables(chan, &vars);
07537
07538 if (ast_str_strlen(vars)) {
07539 ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
07540 }
07541
07542 chan = ast_channel_unref(chan);
07543
07544 return CLI_SUCCESS;
07545 }
07546
07547 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07548 {
07549 switch (cmd) {
07550 case CLI_INIT:
07551 e->command = "dialplan set global";
07552 e->usage =
07553 "Usage: dialplan set global <name> <value>\n"
07554 " Set global dialplan variable <name> to <value>\n";
07555 return NULL;
07556 case CLI_GENERATE:
07557 return NULL;
07558 }
07559
07560 if (a->argc != e->args + 2)
07561 return CLI_SHOWUSAGE;
07562
07563 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
07564 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
07565
07566 return CLI_SUCCESS;
07567 }
07568
07569 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07570 {
07571 struct ast_channel *chan;
07572 const char *chan_name, *var_name, *var_value;
07573
07574 switch (cmd) {
07575 case CLI_INIT:
07576 e->command = "dialplan set chanvar";
07577 e->usage =
07578 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
07579 " Set channel variable <varname> to <value>\n";
07580 return NULL;
07581 case CLI_GENERATE:
07582 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
07583 }
07584
07585 if (a->argc != e->args + 3)
07586 return CLI_SHOWUSAGE;
07587
07588 chan_name = a->argv[e->args];
07589 var_name = a->argv[e->args + 1];
07590 var_value = a->argv[e->args + 2];
07591
07592 if (!(chan = ast_channel_get_by_name(chan_name))) {
07593 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
07594 return CLI_FAILURE;
07595 }
07596
07597 pbx_builtin_setvar_helper(chan, var_name, var_value);
07598
07599 chan = ast_channel_unref(chan);
07600
07601 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
07602
07603 return CLI_SUCCESS;
07604 }
07605
07606 static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07607 {
07608 int oldval = 0;
07609
07610 switch (cmd) {
07611 case CLI_INIT:
07612 e->command = "dialplan set extenpatternmatchnew true";
07613 e->usage =
07614 "Usage: dialplan set extenpatternmatchnew true|false\n"
07615 " Use the NEW extension pattern matching algorithm, true or false.\n";
07616 return NULL;
07617 case CLI_GENERATE:
07618 return NULL;
07619 }
07620
07621 if (a->argc != 4)
07622 return CLI_SHOWUSAGE;
07623
07624 oldval = pbx_set_extenpatternmatchnew(1);
07625
07626 if (oldval)
07627 ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
07628 else
07629 ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
07630
07631 return CLI_SUCCESS;
07632 }
07633
07634 static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07635 {
07636 int oldval = 0;
07637
07638 switch (cmd) {
07639 case CLI_INIT:
07640 e->command = "dialplan set extenpatternmatchnew false";
07641 e->usage =
07642 "Usage: dialplan set extenpatternmatchnew true|false\n"
07643 " Use the NEW extension pattern matching algorithm, true or false.\n";
07644 return NULL;
07645 case CLI_GENERATE:
07646 return NULL;
07647 }
07648
07649 if (a->argc != 4)
07650 return CLI_SHOWUSAGE;
07651
07652 oldval = pbx_set_extenpatternmatchnew(0);
07653
07654 if (!oldval)
07655 ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
07656 else
07657 ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
07658
07659 return CLI_SUCCESS;
07660 }
07661
07662
07663
07664
07665 static struct ast_cli_entry pbx_cli[] = {
07666 AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
07667 AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
07668 AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
07669 AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
07670 AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
07671 AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
07672 #ifdef AST_DEVMODE
07673 AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
07674 #endif
07675 AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
07676 AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
07677 AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
07678 AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
07679 AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
07680 AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
07681 AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
07682 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
07683 AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
07684 };
07685
07686 static void unreference_cached_app(struct ast_app *app)
07687 {
07688 struct ast_context *context = NULL;
07689 struct ast_exten *eroot = NULL, *e = NULL;
07690
07691 ast_rdlock_contexts();
07692 while ((context = ast_walk_contexts(context))) {
07693 while ((eroot = ast_walk_context_extensions(context, eroot))) {
07694 while ((e = ast_walk_extension_priorities(eroot, e))) {
07695 if (e->cached_app == app)
07696 e->cached_app = NULL;
07697 }
07698 }
07699 }
07700 ast_unlock_contexts();
07701
07702 return;
07703 }
07704
07705 int ast_unregister_application(const char *app)
07706 {
07707 struct ast_app *tmp;
07708
07709 AST_RWLIST_WRLOCK(&apps);
07710 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
07711 if (!strcasecmp(app, tmp->name)) {
07712 unreference_cached_app(tmp);
07713 AST_RWLIST_REMOVE_CURRENT(list);
07714 ast_verb(2, "Unregistered application '%s'\n", tmp->name);
07715 ast_string_field_free_memory(tmp);
07716 ast_free(tmp);
07717 break;
07718 }
07719 }
07720 AST_RWLIST_TRAVERSE_SAFE_END;
07721 AST_RWLIST_UNLOCK(&apps);
07722
07723 return tmp ? 0 : -1;
07724 }
07725
07726 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
07727 {
07728 struct ast_context *tmp, **local_contexts;
07729 struct fake_context search;
07730 int length = sizeof(struct ast_context) + strlen(name) + 1;
07731
07732 if (!contexts_table) {
07733
07734 ast_wrlock_contexts();
07735 if (!contexts_table) {
07736 contexts_table = ast_hashtab_create(17,
07737 ast_hashtab_compare_contexts,
07738 ast_hashtab_resize_java,
07739 ast_hashtab_newsize_java,
07740 ast_hashtab_hash_contexts,
07741 0);
07742 }
07743 ast_unlock_contexts();
07744 }
07745
07746 ast_copy_string(search.name, name, sizeof(search.name));
07747 if (!extcontexts) {
07748 ast_rdlock_contexts();
07749 local_contexts = &contexts;
07750 tmp = ast_hashtab_lookup(contexts_table, &search);
07751 ast_unlock_contexts();
07752 if (tmp) {
07753 tmp->refcount++;
07754 return tmp;
07755 }
07756 } else {
07757 local_contexts = extcontexts;
07758 tmp = ast_hashtab_lookup(exttable, &search);
07759 if (tmp) {
07760 tmp->refcount++;
07761 return tmp;
07762 }
07763 }
07764
07765 if ((tmp = ast_calloc(1, length))) {
07766 ast_rwlock_init(&tmp->lock);
07767 ast_mutex_init(&tmp->macrolock);
07768 strcpy(tmp->name, name);
07769 tmp->root = NULL;
07770 tmp->root_table = NULL;
07771 tmp->registrar = ast_strdup(registrar);
07772 tmp->includes = NULL;
07773 tmp->ignorepats = NULL;
07774 tmp->refcount = 1;
07775 } else {
07776 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
07777 return NULL;
07778 }
07779
07780 if (!extcontexts) {
07781 ast_wrlock_contexts();
07782 tmp->next = *local_contexts;
07783 *local_contexts = tmp;
07784 ast_hashtab_insert_safe(contexts_table, tmp);
07785 ast_unlock_contexts();
07786 ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
07787 ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
07788 } else {
07789 tmp->next = *local_contexts;
07790 if (exttable)
07791 ast_hashtab_insert_immediate(exttable, tmp);
07792
07793 *local_contexts = tmp;
07794 ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
07795 ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
07796 }
07797 return tmp;
07798 }
07799
07800 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
07801
07802 struct store_hint {
07803 char *context;
07804 char *exten;
07805 AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
07806 int laststate;
07807 AST_LIST_ENTRY(store_hint) list;
07808 char data[1];
07809 };
07810
07811 AST_LIST_HEAD_NOLOCK(store_hints, store_hint);
07812
07813 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
07814 {
07815 struct ast_include *i;
07816 struct ast_ignorepat *ip;
07817 struct ast_sw *sw;
07818
07819 ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar);
07820
07821
07822 for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
07823 if (strcmp(ast_get_include_registrar(i), registrar) == 0)
07824 continue;
07825 ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
07826 }
07827
07828
07829 for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
07830 if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
07831 continue;
07832 ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
07833 }
07834
07835
07836 for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
07837 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
07838 continue;
07839 ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
07840 }
07841 }
07842
07843
07844
07845
07846 static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
07847 {
07848 struct ast_context *new = ast_hashtab_lookup(exttable, context);
07849 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
07850 struct ast_hashtab_iter *exten_iter;
07851 struct ast_hashtab_iter *prio_iter;
07852 int insert_count = 0;
07853 int first = 1;
07854
07855
07856
07857
07858
07859
07860 if (context->root_table) {
07861 exten_iter = ast_hashtab_start_traversal(context->root_table);
07862 while ((exten_item=ast_hashtab_next(exten_iter))) {
07863 if (new) {
07864 new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
07865 } else {
07866 new_exten_item = NULL;
07867 }
07868 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
07869 while ((prio_item=ast_hashtab_next(prio_iter))) {
07870 int res1;
07871 char *dupdstr;
07872
07873 if (new_exten_item) {
07874 new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
07875 } else {
07876 new_prio_item = NULL;
07877 }
07878 if (strcmp(prio_item->registrar,registrar) == 0) {
07879 continue;
07880 }
07881
07882 if (!new) {
07883 new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar);
07884 }
07885
07886
07887 if (first) {
07888 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
07889 first = 0;
07890 }
07891
07892 if (!new) {
07893 ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
07894 ast_hashtab_end_traversal(prio_iter);
07895 ast_hashtab_end_traversal(exten_iter);
07896 return;
07897 }
07898
07899
07900
07901 dupdstr = ast_strdup(prio_item->data);
07902
07903 res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
07904 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
07905 if (!res1 && new_exten_item && new_prio_item){
07906 ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
07907 context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
07908 } else {
07909
07910
07911 insert_count++;
07912 }
07913 }
07914 ast_hashtab_end_traversal(prio_iter);
07915 }
07916 ast_hashtab_end_traversal(exten_iter);
07917 } else if (new) {
07918
07919
07920
07921 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
07922 }
07923
07924 if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
07925 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
07926
07927
07928 new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
07929
07930
07931 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
07932 }
07933 }
07934
07935
07936
07937 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
07938 {
07939 double ft;
07940 struct ast_context *tmp;
07941 struct ast_context *oldcontextslist;
07942 struct ast_hashtab *oldtable;
07943 struct store_hints hints_stored = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
07944 struct store_hints hints_removed = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
07945 struct store_hint *saved_hint;
07946 struct ast_hint *hint;
07947 struct ast_exten *exten;
07948 int length;
07949 struct ast_state_cb *thiscb;
07950 struct ast_hashtab_iter *iter;
07951 struct ao2_iterator i;
07952 struct timeval begintime;
07953 struct timeval writelocktime;
07954 struct timeval endlocktime;
07955 struct timeval enddeltime;
07956
07957
07958
07959
07960
07961
07962
07963
07964
07965
07966
07967
07968
07969 begintime = ast_tvnow();
07970 ast_mutex_lock(&context_merge_lock);
07971 ast_wrlock_contexts();
07972
07973 if (!contexts_table) {
07974
07975 contexts_table = exttable;
07976 contexts = *extcontexts;
07977 ast_unlock_contexts();
07978 ast_mutex_unlock(&context_merge_lock);
07979 return;
07980 }
07981
07982 iter = ast_hashtab_start_traversal(contexts_table);
07983 while ((tmp = ast_hashtab_next(iter))) {
07984 context_merge(extcontexts, exttable, tmp, registrar);
07985 }
07986 ast_hashtab_end_traversal(iter);
07987
07988 ao2_lock(hints);
07989 writelocktime = ast_tvnow();
07990
07991
07992 i = ao2_iterator_init(hints, AO2_ITERATOR_DONTLOCK);
07993 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07994 if (ao2_container_count(hint->callbacks)) {
07995 ao2_lock(hint);
07996 if (!hint->exten) {
07997
07998 ao2_unlock(hint);
07999 continue;
08000 }
08001
08002 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2
08003 + sizeof(*saved_hint);
08004 if (!(saved_hint = ast_calloc(1, length))) {
08005 ao2_unlock(hint);
08006 continue;
08007 }
08008
08009
08010 while ((thiscb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
08011 AST_LIST_INSERT_TAIL(&saved_hint->callbacks, thiscb, entry);
08012
08013
08014
08015
08016 }
08017
08018 saved_hint->laststate = hint->laststate;
08019 saved_hint->context = saved_hint->data;
08020 strcpy(saved_hint->data, hint->exten->parent->name);
08021 saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
08022 strcpy(saved_hint->exten, hint->exten->exten);
08023 ao2_unlock(hint);
08024 AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
08025 }
08026 }
08027 ao2_iterator_destroy(&i);
08028
08029
08030 oldtable = contexts_table;
08031 oldcontextslist = contexts;
08032
08033
08034 contexts_table = exttable;
08035 contexts = *extcontexts;
08036
08037
08038
08039
08040
08041 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_stored, list))) {
08042 struct pbx_find_info q = { .stacklen = 0 };
08043
08044 exten = pbx_find_extension(NULL, NULL, &q, saved_hint->context, saved_hint->exten,
08045 PRIORITY_HINT, NULL, "", E_MATCH);
08046
08047
08048
08049
08050
08051 if (exten && exten->exten[0] == '_') {
08052 ast_add_extension_nolock(exten->parent->name, 0, saved_hint->exten,
08053 PRIORITY_HINT, NULL, 0, exten->app, ast_strdup(exten->data), ast_free_ptr,
08054 exten->registrar);
08055
08056 exten = ast_hint_extension_nolock(NULL, saved_hint->context,
08057 saved_hint->exten);
08058 }
08059
08060
08061 hint = exten ? ao2_find(hints, exten, 0) : NULL;
08062 if (!hint) {
08063
08064
08065
08066
08067 AST_LIST_INSERT_HEAD(&hints_removed, saved_hint, list);
08068 } else {
08069 ao2_lock(hint);
08070 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
08071 ao2_link(hint->callbacks, thiscb);
08072
08073 ao2_ref(thiscb, -1);
08074 }
08075 hint->laststate = saved_hint->laststate;
08076 ao2_unlock(hint);
08077 ao2_ref(hint, -1);
08078 ast_free(saved_hint);
08079 }
08080 }
08081
08082 ao2_unlock(hints);
08083 ast_unlock_contexts();
08084
08085
08086
08087
08088
08089 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
08090
08091 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
08092 thiscb->change_cb(saved_hint->context, saved_hint->exten,
08093 AST_EXTENSION_REMOVED, thiscb->data);
08094
08095 ao2_ref(thiscb, -1);
08096 }
08097 ast_free(saved_hint);
08098 }
08099
08100 ast_mutex_unlock(&context_merge_lock);
08101 endlocktime = ast_tvnow();
08102
08103
08104
08105
08106
08107
08108
08109 ast_hashtab_destroy(oldtable, NULL);
08110
08111 for (tmp = oldcontextslist; tmp; ) {
08112 struct ast_context *next;
08113
08114 next = tmp->next;
08115 __ast_internal_context_destroy(tmp);
08116 tmp = next;
08117 }
08118 enddeltime = ast_tvnow();
08119
08120 ft = ast_tvdiff_us(writelocktime, begintime);
08121 ft /= 1000000.0;
08122 ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
08123
08124 ft = ast_tvdiff_us(endlocktime, writelocktime);
08125 ft /= 1000000.0;
08126 ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
08127
08128 ft = ast_tvdiff_us(enddeltime, endlocktime);
08129 ft /= 1000000.0;
08130 ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
08131
08132 ft = ast_tvdiff_us(enddeltime, begintime);
08133 ft /= 1000000.0;
08134 ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
08135 }
08136
08137
08138
08139
08140
08141
08142 int ast_context_add_include(const char *context, const char *include, const char *registrar)
08143 {
08144 int ret = -1;
08145 struct ast_context *c;
08146
08147 c = find_context_locked(context);
08148 if (c) {
08149 ret = ast_context_add_include2(c, include, registrar);
08150 ast_unlock_contexts();
08151 }
08152 return ret;
08153 }
08154
08155
08156
08157
08158
08159 static int lookup_name(const char *s, const char * const names[], int max)
08160 {
08161 int i;
08162
08163 if (names && *s > '9') {
08164 for (i = 0; names[i]; i++) {
08165 if (!strcasecmp(s, names[i])) {
08166 return i;
08167 }
08168 }
08169 }
08170
08171
08172 if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
08173
08174 return i - 1;
08175 }
08176 return -1;
08177 }
08178
08179
08180
08181
08182 static unsigned get_range(char *src, int max, const char * const names[], const char *msg)
08183 {
08184 int start, end;
08185 unsigned int mask = 0;
08186 char *part;
08187
08188
08189 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
08190 return (1 << max) - 1;
08191 }
08192
08193 while ((part = strsep(&src, "&"))) {
08194
08195 char *endpart = strchr(part, '-');
08196 if (endpart) {
08197 *endpart++ = '\0';
08198 }
08199
08200 if ((start = lookup_name(part, names, max)) < 0) {
08201 ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
08202 continue;
08203 }
08204 if (endpart) {
08205 if ((end = lookup_name(endpart, names, max)) < 0) {
08206 ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
08207 continue;
08208 }
08209 } else {
08210 end = start;
08211 }
08212
08213 mask |= (1 << end);
08214 while (start != end) {
08215 mask |= (1 << start);
08216 if (++start >= max) {
08217 start = 0;
08218 }
08219 }
08220 }
08221 return mask;
08222 }
08223
08224
08225 static void get_timerange(struct ast_timing *i, char *times)
08226 {
08227 char *endpart, *part;
08228 int x;
08229 int st_h, st_m;
08230 int endh, endm;
08231 int minute_start, minute_end;
08232
08233
08234 memset(i->minmask, 0, sizeof(i->minmask));
08235
08236
08237
08238 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
08239
08240 for (x = 0; x < 48; x++) {
08241 i->minmask[x] = 0x3fffffff;
08242 }
08243 return;
08244 }
08245
08246 while ((part = strsep(×, "&"))) {
08247 if (!(endpart = strchr(part, '-'))) {
08248 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
08249 ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
08250 continue;
08251 }
08252 i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
08253 continue;
08254 }
08255 *endpart++ = '\0';
08256
08257 while (*endpart && !isdigit(*endpart)) {
08258 endpart++;
08259 }
08260 if (!*endpart) {
08261 ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
08262 continue;
08263 }
08264 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
08265 ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
08266 continue;
08267 }
08268 if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
08269 ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
08270 continue;
08271 }
08272 minute_start = st_h * 60 + st_m;
08273 minute_end = endh * 60 + endm;
08274
08275 for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
08276 i->minmask[x / 30] |= (1 << (x % 30));
08277 }
08278
08279 i->minmask[x / 30] |= (1 << (x % 30));
08280 }
08281
08282 return;
08283 }
08284
08285 static const char * const days[] =
08286 {
08287 "sun",
08288 "mon",
08289 "tue",
08290 "wed",
08291 "thu",
08292 "fri",
08293 "sat",
08294 NULL,
08295 };
08296
08297 static const char * const months[] =
08298 {
08299 "jan",
08300 "feb",
08301 "mar",
08302 "apr",
08303 "may",
08304 "jun",
08305 "jul",
08306 "aug",
08307 "sep",
08308 "oct",
08309 "nov",
08310 "dec",
08311 NULL,
08312 };
08313
08314 int ast_build_timing(struct ast_timing *i, const char *info_in)
08315 {
08316 char *info;
08317 int j, num_fields, last_sep = -1;
08318
08319 i->timezone = NULL;
08320
08321
08322 if (ast_strlen_zero(info_in)) {
08323 return 0;
08324 }
08325
08326
08327 info = ast_strdupa(info_in);
08328
08329
08330 for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
08331 if (info[j] == ',') {
08332 last_sep = j;
08333 num_fields++;
08334 }
08335 }
08336
08337
08338 if (num_fields == 5) {
08339 i->timezone = ast_strdup(info + last_sep + 1);
08340 }
08341
08342
08343 i->monthmask = 0xfff;
08344 i->daymask = 0x7fffffffU;
08345 i->dowmask = 0x7f;
08346
08347 get_timerange(i, strsep(&info, "|,"));
08348 if (info)
08349 i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
08350 if (info)
08351 i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
08352 if (info)
08353 i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
08354 return 1;
08355 }
08356
08357 int ast_check_timing(const struct ast_timing *i)
08358 {
08359 return ast_check_timing2(i, ast_tvnow());
08360 }
08361
08362 int ast_check_timing2(const struct ast_timing *i, const struct timeval tv)
08363 {
08364 struct ast_tm tm;
08365
08366 ast_localtime(&tv, &tm, i->timezone);
08367
08368
08369 if (!(i->monthmask & (1 << tm.tm_mon)))
08370 return 0;
08371
08372
08373
08374 if (!(i->daymask & (1 << (tm.tm_mday-1))))
08375 return 0;
08376
08377
08378 if (!(i->dowmask & (1 << tm.tm_wday)))
08379 return 0;
08380
08381
08382 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
08383 ast_log(LOG_WARNING, "Insane time...\n");
08384 return 0;
08385 }
08386
08387
08388
08389 if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
08390 return 0;
08391
08392
08393 return 1;
08394 }
08395
08396 int ast_destroy_timing(struct ast_timing *i)
08397 {
08398 if (i->timezone) {
08399 ast_free(i->timezone);
08400 i->timezone = NULL;
08401 }
08402 return 0;
08403 }
08404
08405
08406
08407
08408
08409
08410
08411 int ast_context_add_include2(struct ast_context *con, const char *value,
08412 const char *registrar)
08413 {
08414 struct ast_include *new_include;
08415 char *c;
08416 struct ast_include *i, *il = NULL;
08417 int length;
08418 char *p;
08419
08420 length = sizeof(struct ast_include);
08421 length += 2 * (strlen(value) + 1);
08422
08423
08424 if (!(new_include = ast_calloc(1, length)))
08425 return -1;
08426
08427
08428
08429 p = new_include->stuff;
08430 new_include->name = p;
08431 strcpy(p, value);
08432 p += strlen(value) + 1;
08433 new_include->rname = p;
08434 strcpy(p, value);
08435
08436 if ( (c = strchr(p, ',')) ) {
08437 *c++ = '\0';
08438 new_include->hastime = ast_build_timing(&(new_include->timing), c);
08439 }
08440 new_include->next = NULL;
08441 new_include->registrar = registrar;
08442
08443 ast_wrlock_context(con);
08444
08445
08446 for (i = con->includes; i; i = i->next) {
08447 if (!strcasecmp(i->name, new_include->name)) {
08448 ast_destroy_timing(&(new_include->timing));
08449 ast_free(new_include);
08450 ast_unlock_context(con);
08451 errno = EEXIST;
08452 return -1;
08453 }
08454 il = i;
08455 }
08456
08457
08458 if (il)
08459 il->next = new_include;
08460 else
08461 con->includes = new_include;
08462 ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
08463
08464 ast_unlock_context(con);
08465
08466 return 0;
08467 }
08468
08469
08470
08471
08472
08473
08474 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
08475 {
08476 int ret = -1;
08477 struct ast_context *c;
08478
08479 c = find_context_locked(context);
08480 if (c) {
08481 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
08482 ast_unlock_contexts();
08483 }
08484 return ret;
08485 }
08486
08487
08488
08489
08490
08491
08492
08493
08494 int ast_context_add_switch2(struct ast_context *con, const char *value,
08495 const char *data, int eval, const char *registrar)
08496 {
08497 struct ast_sw *new_sw;
08498 struct ast_sw *i;
08499 int length;
08500 char *p;
08501
08502 length = sizeof(struct ast_sw);
08503 length += strlen(value) + 1;
08504 if (data)
08505 length += strlen(data);
08506 length++;
08507
08508
08509 if (!(new_sw = ast_calloc(1, length)))
08510 return -1;
08511
08512 p = new_sw->stuff;
08513 new_sw->name = p;
08514 strcpy(new_sw->name, value);
08515 p += strlen(value) + 1;
08516 new_sw->data = p;
08517 if (data) {
08518 strcpy(new_sw->data, data);
08519 p += strlen(data) + 1;
08520 } else {
08521 strcpy(new_sw->data, "");
08522 p++;
08523 }
08524 new_sw->eval = eval;
08525 new_sw->registrar = registrar;
08526
08527
08528 ast_wrlock_context(con);
08529
08530
08531 AST_LIST_TRAVERSE(&con->alts, i, list) {
08532 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
08533 ast_free(new_sw);
08534 ast_unlock_context(con);
08535 errno = EEXIST;
08536 return -1;
08537 }
08538 }
08539
08540
08541 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
08542
08543 ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
08544
08545 ast_unlock_context(con);
08546
08547 return 0;
08548 }
08549
08550
08551
08552
08553
08554 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
08555 {
08556 int ret = -1;
08557 struct ast_context *c;
08558
08559 c = find_context_locked(context);
08560 if (c) {
08561 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
08562 ast_unlock_contexts();
08563 }
08564 return ret;
08565 }
08566
08567 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
08568 {
08569 struct ast_ignorepat *ip, *ipl = NULL;
08570
08571 ast_wrlock_context(con);
08572
08573 for (ip = con->ignorepats; ip; ip = ip->next) {
08574 if (!strcmp(ip->pattern, ignorepat) &&
08575 (!registrar || (registrar == ip->registrar))) {
08576 if (ipl) {
08577 ipl->next = ip->next;
08578 ast_free(ip);
08579 } else {
08580 con->ignorepats = ip->next;
08581 ast_free(ip);
08582 }
08583 ast_unlock_context(con);
08584 return 0;
08585 }
08586 ipl = ip;
08587 }
08588
08589 ast_unlock_context(con);
08590 errno = EINVAL;
08591 return -1;
08592 }
08593
08594
08595
08596
08597
08598 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
08599 {
08600 int ret = -1;
08601 struct ast_context *c;
08602
08603 c = find_context_locked(context);
08604 if (c) {
08605 ret = ast_context_add_ignorepat2(c, value, registrar);
08606 ast_unlock_contexts();
08607 }
08608 return ret;
08609 }
08610
08611 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
08612 {
08613 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
08614 int length;
08615 char *pattern;
08616 length = sizeof(struct ast_ignorepat);
08617 length += strlen(value) + 1;
08618 if (!(ignorepat = ast_calloc(1, length)))
08619 return -1;
08620
08621
08622
08623
08624
08625
08626 pattern = (char *) ignorepat->pattern;
08627 strcpy(pattern, value);
08628 ignorepat->next = NULL;
08629 ignorepat->registrar = registrar;
08630 ast_wrlock_context(con);
08631 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
08632 ignorepatl = ignorepatc;
08633 if (!strcasecmp(ignorepatc->pattern, value)) {
08634
08635 ast_unlock_context(con);
08636 ast_free(ignorepat);
08637 errno = EEXIST;
08638 return -1;
08639 }
08640 }
08641 if (ignorepatl)
08642 ignorepatl->next = ignorepat;
08643 else
08644 con->ignorepats = ignorepat;
08645 ast_unlock_context(con);
08646 return 0;
08647
08648 }
08649
08650 int ast_ignore_pattern(const char *context, const char *pattern)
08651 {
08652 struct ast_context *con = ast_context_find(context);
08653
08654 if (con) {
08655 struct ast_ignorepat *pat;
08656
08657 for (pat = con->ignorepats; pat; pat = pat->next) {
08658 if (ast_extension_match(pat->pattern, pattern))
08659 return 1;
08660 }
08661 }
08662
08663 return 0;
08664 }
08665
08666
08667
08668
08669
08670
08671 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
08672 int priority, const char *label, const char *callerid,
08673 const char *application, void *data, void (*datad)(void *), const char *registrar)
08674 {
08675 int ret = -1;
08676 struct ast_context *c;
08677
08678 c = find_context(context);
08679 if (c) {
08680 ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
08681 application, data, datad, registrar, 1);
08682 }
08683
08684 return ret;
08685 }
08686
08687
08688
08689
08690
08691 int ast_add_extension(const char *context, int replace, const char *extension,
08692 int priority, const char *label, const char *callerid,
08693 const char *application, void *data, void (*datad)(void *), const char *registrar)
08694 {
08695 int ret = -1;
08696 struct ast_context *c;
08697
08698 c = find_context_locked(context);
08699 if (c) {
08700 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
08701 application, data, datad, registrar);
08702 ast_unlock_contexts();
08703 }
08704
08705 return ret;
08706 }
08707
08708 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
08709 {
08710 if (!chan)
08711 return -1;
08712
08713 ast_channel_lock(chan);
08714
08715 if (!ast_strlen_zero(context))
08716 ast_copy_string(chan->context, context, sizeof(chan->context));
08717 if (!ast_strlen_zero(exten))
08718 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
08719 if (priority > -1) {
08720 chan->priority = priority;
08721
08722 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
08723 chan->priority--;
08724 }
08725
08726 ast_channel_unlock(chan);
08727
08728 return 0;
08729 }
08730
08731 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
08732 {
08733 int res = 0;
08734 struct ast_channel *tmpchan;
08735 struct {
08736 char *accountcode;
08737 char *exten;
08738 char *context;
08739 char *linkedid;
08740 char *name;
08741 struct ast_cdr *cdr;
08742 int amaflags;
08743 int state;
08744 format_t readformat;
08745 format_t writeformat;
08746 } tmpvars = { 0, };
08747
08748 ast_channel_lock(chan);
08749 if (chan->pbx) {
08750 ast_explicit_goto(chan, context, exten, priority + 1);
08751 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
08752 ast_channel_unlock(chan);
08753 return res;
08754 }
08755
08756
08757
08758
08759 tmpvars.accountcode = ast_strdupa(chan->accountcode);
08760 tmpvars.exten = ast_strdupa(chan->exten);
08761 tmpvars.context = ast_strdupa(chan->context);
08762 tmpvars.linkedid = ast_strdupa(chan->linkedid);
08763 tmpvars.name = ast_strdupa(chan->name);
08764 tmpvars.amaflags = chan->amaflags;
08765 tmpvars.state = chan->_state;
08766 tmpvars.writeformat = chan->writeformat;
08767 tmpvars.readformat = chan->readformat;
08768 tmpvars.cdr = chan->cdr ? ast_cdr_dup(chan->cdr) : NULL;
08769
08770 ast_channel_unlock(chan);
08771
08772
08773
08774 if (!(tmpchan = ast_channel_alloc(0, tmpvars.state, 0, 0, tmpvars.accountcode, tmpvars.exten, tmpvars.context, tmpvars.linkedid, tmpvars.amaflags, "AsyncGoto/%s", tmpvars.name))) {
08775 ast_cdr_discard(tmpvars.cdr);
08776 return -1;
08777 }
08778
08779
08780 if (tmpvars.cdr) {
08781 ast_cdr_discard(tmpchan->cdr);
08782 tmpchan->cdr = tmpvars.cdr;
08783 tmpvars.cdr = NULL;
08784 }
08785
08786
08787 tmpchan->readformat = tmpvars.readformat;
08788 tmpchan->writeformat = tmpvars.writeformat;
08789
08790
08791 ast_explicit_goto(tmpchan, S_OR(context, tmpvars.context), S_OR(exten, tmpvars.exten), priority);
08792
08793
08794 if (ast_channel_masquerade(tmpchan, chan)) {
08795
08796
08797 ast_hangup(tmpchan);
08798 tmpchan = NULL;
08799 res = -1;
08800 } else {
08801 ast_do_masquerade(tmpchan);
08802
08803 if (ast_pbx_start(tmpchan)) {
08804 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
08805 ast_hangup(tmpchan);
08806 res = -1;
08807 }
08808 }
08809
08810 return res;
08811 }
08812
08813 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
08814 {
08815 struct ast_channel *chan;
08816 int res = -1;
08817
08818 if ((chan = ast_channel_get_by_name(channame))) {
08819 res = ast_async_goto(chan, context, exten, priority);
08820 chan = ast_channel_unref(chan);
08821 }
08822
08823 return res;
08824 }
08825
08826
08827 static int ext_strncpy(char *dst, const char *src, int len)
08828 {
08829 int count = 0;
08830 int insquares = 0;
08831
08832 while (*src && (count < len - 1)) {
08833 if (*src == '[') {
08834 insquares = 1;
08835 } else if (*src == ']') {
08836 insquares = 0;
08837 } else if (*src == ' ' && !insquares) {
08838 src++;
08839 continue;
08840 }
08841 *dst = *src;
08842 dst++;
08843 src++;
08844 count++;
08845 }
08846 *dst = '\0';
08847
08848 return count;
08849 }
08850
08851
08852
08853
08854
08855
08856 static int add_priority(struct ast_context *con, struct ast_exten *tmp,
08857 struct ast_exten *el, struct ast_exten *e, int replace)
08858 {
08859 struct ast_exten *ep;
08860 struct ast_exten *eh=e;
08861 int repeated_label = 0;
08862
08863 for (ep = NULL; e ; ep = e, e = e->peer) {
08864 if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
08865 if (strcmp(e->exten, tmp->exten)) {
08866 ast_log(LOG_WARNING,
08867 "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
08868 tmp->exten, tmp->priority, con->name, tmp->label, e->exten, e->priority);
08869 } else {
08870 ast_log(LOG_WARNING,
08871 "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
08872 tmp->exten, tmp->priority, con->name, tmp->label, e->priority);
08873 }
08874 repeated_label = 1;
08875 }
08876 if (e->priority >= tmp->priority) {
08877 break;
08878 }
08879 }
08880
08881 if (repeated_label) {
08882 tmp->label = NULL;
08883 }
08884
08885 if (!e) {
08886 ast_hashtab_insert_safe(eh->peer_table, tmp);
08887
08888 if (tmp->label) {
08889 ast_hashtab_insert_safe(eh->peer_label_table, tmp);
08890 }
08891 ep->peer = tmp;
08892 return 0;
08893 }
08894 if (e->priority == tmp->priority) {
08895
08896
08897 if (!replace) {
08898 if (strcmp(e->exten, tmp->exten)) {
08899 ast_log(LOG_WARNING,
08900 "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
08901 tmp->exten, tmp->priority, con->name, e->exten);
08902 } else {
08903 ast_log(LOG_WARNING,
08904 "Unable to register extension '%s' priority %d in '%s', already in use\n",
08905 tmp->exten, tmp->priority, con->name);
08906 }
08907 if (tmp->datad) {
08908 tmp->datad(tmp->data);
08909
08910 tmp->data = NULL;
08911 }
08912
08913 ast_free(tmp);
08914 return -1;
08915 }
08916
08917
08918
08919 tmp->next = e->next;
08920 tmp->peer = e->peer;
08921 if (ep) {
08922 ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
08923
08924 if (e->label) {
08925 ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
08926 }
08927
08928 ast_hashtab_insert_safe(eh->peer_table,tmp);
08929 if (tmp->label) {
08930 ast_hashtab_insert_safe(eh->peer_label_table,tmp);
08931 }
08932
08933 ep->peer = tmp;
08934 } else if (el) {
08935 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
08936 tmp->peer_table = e->peer_table;
08937 tmp->peer_label_table = e->peer_label_table;
08938 ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
08939 ast_hashtab_insert_safe(tmp->peer_table,tmp);
08940 if (e->label) {
08941 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
08942 }
08943 if (tmp->label) {
08944 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
08945 }
08946
08947 ast_hashtab_remove_object_via_lookup(con->root_table, e);
08948 ast_hashtab_insert_safe(con->root_table, tmp);
08949 el->next = tmp;
08950
08951
08952 if (x) {
08953 if (x->exten) {
08954 x->exten = tmp;
08955 } else {
08956 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
08957 }
08958 }
08959 } else {
08960 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
08961 ast_hashtab_remove_object_via_lookup(con->root_table, e);
08962 ast_hashtab_insert_safe(con->root_table, tmp);
08963 tmp->peer_table = e->peer_table;
08964 tmp->peer_label_table = e->peer_label_table;
08965 ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
08966 ast_hashtab_insert_safe(tmp->peer_table, tmp);
08967 if (e->label) {
08968 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
08969 }
08970 if (tmp->label) {
08971 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
08972 }
08973
08974 ast_hashtab_remove_object_via_lookup(con->root_table, e);
08975 ast_hashtab_insert_safe(con->root_table, tmp);
08976 con->root = tmp;
08977
08978
08979 if (x) {
08980 if (x->exten) {
08981 x->exten = tmp;
08982 } else {
08983 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
08984 }
08985 }
08986 }
08987 if (tmp->priority == PRIORITY_HINT)
08988 ast_change_hint(e,tmp);
08989
08990 if (e->datad)
08991 e->datad(e->data);
08992 ast_free(e);
08993 } else {
08994 tmp->peer = e;
08995 tmp->next = e->next;
08996 if (ep) {
08997 if (tmp->label) {
08998 ast_hashtab_insert_safe(eh->peer_label_table, tmp);
08999 }
09000 ast_hashtab_insert_safe(eh->peer_table, tmp);
09001 ep->peer = tmp;
09002 } else {
09003 tmp->peer_table = e->peer_table;
09004 tmp->peer_label_table = e->peer_label_table;
09005 e->peer_table = 0;
09006 e->peer_label_table = 0;
09007 ast_hashtab_insert_safe(tmp->peer_table, tmp);
09008 if (tmp->label) {
09009 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
09010 }
09011 ast_hashtab_remove_object_via_lookup(con->root_table, e);
09012 ast_hashtab_insert_safe(con->root_table, tmp);
09013 if (el)
09014 el->next = tmp;
09015 else
09016 con->root = tmp;
09017 e->next = NULL;
09018 }
09019
09020 if (tmp->priority == PRIORITY_HINT) {
09021 ast_add_hint(tmp);
09022 }
09023 }
09024 return 0;
09025 }
09026
09027
09028
09029
09030
09031
09032
09033
09034
09035
09036
09037
09038
09039
09040
09041
09042
09043
09044
09045
09046
09047
09048
09049
09050
09051
09052 int ast_add_extension2(struct ast_context *con,
09053 int replace, const char *extension, int priority, const char *label, const char *callerid,
09054 const char *application, void *data, void (*datad)(void *),
09055 const char *registrar)
09056 {
09057 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
09058 application, data, datad, registrar, 1);
09059 }
09060
09061
09062
09063
09064
09065
09066
09067
09068 static int ast_add_extension2_lockopt(struct ast_context *con,
09069 int replace, const char *extension, int priority, const char *label, const char *callerid,
09070 const char *application, void *data, void (*datad)(void *),
09071 const char *registrar, int lock_context)
09072 {
09073
09074
09075
09076
09077
09078
09079 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
09080 int res;
09081 int length;
09082 char *p;
09083 char expand_buf[VAR_BUF_SIZE];
09084 struct ast_exten dummy_exten = {0};
09085 char dummy_name[1024];
09086
09087 if (ast_strlen_zero(extension)) {
09088 ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
09089 con->name);
09090 return -1;
09091 }
09092
09093
09094 if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
09095 struct ast_channel *c = ast_dummy_channel_alloc();
09096
09097 if (c) {
09098 ast_copy_string(c->exten, extension, sizeof(c->exten));
09099 ast_copy_string(c->context, con->name, sizeof(c->context));
09100 }
09101 pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
09102 application = expand_buf;
09103 if (c) {
09104 ast_channel_unref(c);
09105 }
09106 }
09107
09108 length = sizeof(struct ast_exten);
09109 length += strlen(extension) + 1;
09110 length += strlen(application) + 1;
09111 if (label)
09112 length += strlen(label) + 1;
09113 if (callerid)
09114 length += strlen(callerid) + 1;
09115 else
09116 length ++;
09117
09118
09119 if (!(tmp = ast_calloc(1, length)))
09120 return -1;
09121
09122 if (ast_strlen_zero(label))
09123 label = 0;
09124
09125
09126 p = tmp->stuff;
09127 if (label) {
09128 tmp->label = p;
09129 strcpy(p, label);
09130 p += strlen(label) + 1;
09131 }
09132 tmp->exten = p;
09133 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
09134 tmp->priority = priority;
09135 tmp->cidmatch = p;
09136
09137
09138 if (callerid) {
09139 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
09140 tmp->matchcid = AST_EXT_MATCHCID_ON;
09141 } else {
09142 *p++ = '\0';
09143 tmp->matchcid = AST_EXT_MATCHCID_OFF;
09144 }
09145 tmp->app = p;
09146 strcpy(p, application);
09147 tmp->parent = con;
09148 tmp->data = data;
09149 tmp->datad = datad;
09150 tmp->registrar = registrar;
09151
09152 if (lock_context) {
09153 ast_wrlock_context(con);
09154 }
09155
09156 if (con->pattern_tree) {
09157
09158 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
09159 dummy_exten.exten = dummy_name;
09160 dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
09161 dummy_exten.cidmatch = 0;
09162 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
09163 if (!tmp2) {
09164
09165 add_exten_to_pattern_tree(con, tmp, 0);
09166 ast_hashtab_insert_safe(con->root_table, tmp);
09167 }
09168 }
09169 res = 0;
09170 for (e = con->root; e; el = e, e = e->next) {
09171 res = ext_cmp(e->exten, tmp->exten);
09172 if (res == 0) {
09173 if (e->matchcid == AST_EXT_MATCHCID_OFF && tmp->matchcid == AST_EXT_MATCHCID_OFF)
09174 res = 0;
09175 else if (tmp->matchcid == AST_EXT_MATCHCID_ON && e->matchcid == AST_EXT_MATCHCID_OFF)
09176 res = 1;
09177 else if (e->matchcid == AST_EXT_MATCHCID_ON && tmp->matchcid == AST_EXT_MATCHCID_OFF)
09178 res = -1;
09179 else
09180 res = ext_cmp(e->cidmatch, tmp->cidmatch);
09181 }
09182 if (res >= 0)
09183 break;
09184 }
09185 if (e && res == 0) {
09186 res = add_priority(con, tmp, el, e, replace);
09187 if (lock_context) {
09188 ast_unlock_context(con);
09189 }
09190 if (res < 0) {
09191 errno = EEXIST;
09192 return 0;
09193 }
09194 } else {
09195
09196
09197
09198
09199 tmp->next = e;
09200 if (el) {
09201 el->next = tmp;
09202 tmp->peer_table = ast_hashtab_create(13,
09203 hashtab_compare_exten_numbers,
09204 ast_hashtab_resize_java,
09205 ast_hashtab_newsize_java,
09206 hashtab_hash_priority,
09207 0);
09208 tmp->peer_label_table = ast_hashtab_create(7,
09209 hashtab_compare_exten_labels,
09210 ast_hashtab_resize_java,
09211 ast_hashtab_newsize_java,
09212 hashtab_hash_labels,
09213 0);
09214 if (label) {
09215 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
09216 }
09217 ast_hashtab_insert_safe(tmp->peer_table, tmp);
09218 } else {
09219 if (!con->root_table)
09220 con->root_table = ast_hashtab_create(27,
09221 hashtab_compare_extens,
09222 ast_hashtab_resize_java,
09223 ast_hashtab_newsize_java,
09224 hashtab_hash_extens,
09225 0);
09226 con->root = tmp;
09227 con->root->peer_table = ast_hashtab_create(13,
09228 hashtab_compare_exten_numbers,
09229 ast_hashtab_resize_java,
09230 ast_hashtab_newsize_java,
09231 hashtab_hash_priority,
09232 0);
09233 con->root->peer_label_table = ast_hashtab_create(7,
09234 hashtab_compare_exten_labels,
09235 ast_hashtab_resize_java,
09236 ast_hashtab_newsize_java,
09237 hashtab_hash_labels,
09238 0);
09239 if (label) {
09240 ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
09241 }
09242 ast_hashtab_insert_safe(con->root->peer_table, tmp);
09243
09244 }
09245 ast_hashtab_insert_safe(con->root_table, tmp);
09246 if (lock_context) {
09247 ast_unlock_context(con);
09248 }
09249 if (tmp->priority == PRIORITY_HINT) {
09250 ast_add_hint(tmp);
09251 }
09252 }
09253 if (option_debug) {
09254 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
09255 ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
09256 tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
09257 } else {
09258 ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
09259 tmp->exten, tmp->priority, con->name, con);
09260 }
09261 }
09262
09263 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
09264 ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
09265 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
09266 } else {
09267 ast_verb(3, "Added extension '%s' priority %d to %s\n",
09268 tmp->exten, tmp->priority, con->name);
09269 }
09270
09271 return 0;
09272 }
09273
09274 struct async_stat {
09275 pthread_t p;
09276 struct ast_channel *chan;
09277 char context[AST_MAX_CONTEXT];
09278 char exten[AST_MAX_EXTENSION];
09279 int priority;
09280 int timeout;
09281 char app[AST_MAX_EXTENSION];
09282 char appdata[1024];
09283 };
09284
09285 static void *async_wait(void *data)
09286 {
09287 struct async_stat *as = data;
09288 struct ast_channel *chan = as->chan;
09289 int timeout = as->timeout;
09290 int res;
09291 struct ast_frame *f;
09292 struct ast_app *app;
09293 struct timeval start = ast_tvnow();
09294 int ms;
09295
09296 while ((ms = ast_remaining_ms(start, timeout)) &&
09297 chan->_state != AST_STATE_UP) {
09298 res = ast_waitfor(chan, ms);
09299 if (res < 1)
09300 break;
09301
09302 f = ast_read(chan);
09303 if (!f)
09304 break;
09305 if (f->frametype == AST_FRAME_CONTROL) {
09306 if ((f->subclass.integer == AST_CONTROL_BUSY) ||
09307 (f->subclass.integer == AST_CONTROL_CONGESTION) ) {
09308 ast_frfree(f);
09309 break;
09310 }
09311 }
09312 ast_frfree(f);
09313 }
09314 if (chan->_state == AST_STATE_UP) {
09315 if (!ast_strlen_zero(as->app)) {
09316 app = pbx_findapp(as->app);
09317 if (app) {
09318 ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
09319 pbx_exec(chan, app, as->appdata);
09320 } else
09321 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
09322 } else {
09323 if (!ast_strlen_zero(as->context))
09324 ast_copy_string(chan->context, as->context, sizeof(chan->context));
09325 if (!ast_strlen_zero(as->exten))
09326 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
09327 if (as->priority > 0)
09328 chan->priority = as->priority;
09329
09330 if (ast_pbx_run(chan)) {
09331 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
09332 } else {
09333
09334 chan = NULL;
09335 }
09336 }
09337 }
09338 ast_free(as);
09339 if (chan)
09340 ast_hangup(chan);
09341 return NULL;
09342 }
09343
09344
09345
09346
09347
09348 static int ast_pbx_outgoing_cdr_failed(void)
09349 {
09350
09351 struct ast_channel *chan = ast_dummy_channel_alloc();
09352
09353 if (!chan)
09354 return -1;
09355
09356 chan->cdr = ast_cdr_alloc();
09357 if (!chan->cdr) {
09358
09359 chan = ast_channel_unref(chan);
09360 return -1;
09361 }
09362
09363
09364 ast_cdr_init(chan->cdr, chan);
09365 ast_cdr_start(chan->cdr);
09366 ast_cdr_end(chan->cdr);
09367 ast_cdr_failed(chan->cdr);
09368 ast_cdr_detach(chan->cdr);
09369 chan->cdr = NULL;
09370 chan = ast_channel_unref(chan);
09371
09372 return 0;
09373 }
09374
09375 int ast_pbx_outgoing_exten(const char *type, format_t format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
09376 {
09377 struct ast_channel *chan;
09378 struct async_stat *as;
09379 int res = -1, cdr_res = -1;
09380 struct outgoing_helper oh;
09381
09382 if (synchronous) {
09383 oh.context = context;
09384 oh.exten = exten;
09385 oh.priority = priority;
09386 oh.cid_num = cid_num;
09387 oh.cid_name = cid_name;
09388 oh.account = account;
09389 oh.vars = vars;
09390 oh.parent_channel = NULL;
09391
09392 chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
09393 if (channel) {
09394 *channel = chan;
09395 if (chan)
09396 ast_channel_lock(chan);
09397 }
09398 if (chan) {
09399 if (chan->_state == AST_STATE_UP) {
09400 res = 0;
09401 ast_verb(4, "Channel %s was answered.\n", chan->name);
09402
09403 if (synchronous > 1) {
09404 if (channel)
09405 ast_channel_unlock(chan);
09406 if (ast_pbx_run(chan)) {
09407 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
09408 if (channel)
09409 *channel = NULL;
09410 ast_hangup(chan);
09411 chan = NULL;
09412 res = -1;
09413 }
09414 } else {
09415 if (ast_pbx_start(chan)) {
09416 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
09417 if (channel) {
09418 *channel = NULL;
09419 ast_channel_unlock(chan);
09420 }
09421 ast_hangup(chan);
09422 res = -1;
09423 }
09424 chan = NULL;
09425 }
09426 } else {
09427 ast_verb(4, "Channel %s was never answered.\n", chan->name);
09428
09429 if (chan->cdr) {
09430
09431
09432 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
09433 ast_cdr_failed(chan->cdr);
09434 }
09435
09436 if (channel) {
09437 *channel = NULL;
09438 ast_channel_unlock(chan);
09439 }
09440 ast_hangup(chan);
09441 chan = NULL;
09442 }
09443 }
09444
09445 if (res < 0) {
09446 if (*reason == 0) {
09447
09448 cdr_res = ast_pbx_outgoing_cdr_failed();
09449 if (cdr_res != 0) {
09450 res = cdr_res;
09451 goto outgoing_exten_cleanup;
09452 }
09453 }
09454
09455
09456
09457 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
09458 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", NULL, 0, "OutgoingSpoolFailed");
09459 if (chan) {
09460 char failed_reason[4] = "";
09461 if (!ast_strlen_zero(context))
09462 ast_copy_string(chan->context, context, sizeof(chan->context));
09463 set_ext_pri(chan, "failed", 1);
09464 ast_set_variables(chan, vars);
09465 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
09466 pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
09467 if (account)
09468 ast_cdr_setaccount(chan, account);
09469 if (ast_pbx_run(chan)) {
09470 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
09471 ast_hangup(chan);
09472 }
09473 chan = NULL;
09474 }
09475 }
09476 }
09477 } else {
09478 if (!(as = ast_calloc(1, sizeof(*as)))) {
09479 res = -1;
09480 goto outgoing_exten_cleanup;
09481 }
09482 chan = ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name);
09483 if (channel) {
09484 *channel = chan;
09485 if (chan)
09486 ast_channel_lock(chan);
09487 }
09488 if (!chan) {
09489 ast_free(as);
09490 res = -1;
09491 goto outgoing_exten_cleanup;
09492 }
09493 as->chan = chan;
09494 ast_copy_string(as->context, context, sizeof(as->context));
09495 set_ext_pri(as->chan, exten, priority);
09496 as->timeout = timeout;
09497 ast_set_variables(chan, vars);
09498 if (account)
09499 ast_cdr_setaccount(chan, account);
09500 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
09501 ast_log(LOG_WARNING, "Failed to start async wait\n");
09502 ast_free(as);
09503 if (channel) {
09504 *channel = NULL;
09505 ast_channel_unlock(chan);
09506 }
09507 ast_hangup(chan);
09508 res = -1;
09509 goto outgoing_exten_cleanup;
09510 }
09511 res = 0;
09512 }
09513 outgoing_exten_cleanup:
09514 ast_variables_destroy(vars);
09515 return res;
09516 }
09517
09518 struct app_tmp {
09519 struct ast_channel *chan;
09520 pthread_t t;
09521 AST_DECLARE_STRING_FIELDS (
09522 AST_STRING_FIELD(app);
09523 AST_STRING_FIELD(data);
09524 );
09525 };
09526
09527
09528 static void *ast_pbx_run_app(void *data)
09529 {
09530 struct app_tmp *tmp = data;
09531 struct ast_app *app;
09532 app = pbx_findapp(tmp->app);
09533 if (app) {
09534 ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
09535 pbx_exec(tmp->chan, app, tmp->data);
09536 } else
09537 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
09538 ast_hangup(tmp->chan);
09539 ast_string_field_free_memory(tmp);
09540 ast_free(tmp);
09541 return NULL;
09542 }
09543
09544 int ast_pbx_outgoing_app(const char *type, format_t format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
09545 {
09546 struct ast_channel *chan;
09547 struct app_tmp *tmp;
09548 int res = -1, cdr_res = -1;
09549 struct outgoing_helper oh;
09550
09551 memset(&oh, 0, sizeof(oh));
09552 oh.vars = vars;
09553 oh.account = account;
09554
09555 if (locked_channel)
09556 *locked_channel = NULL;
09557 if (ast_strlen_zero(app)) {
09558 res = -1;
09559 goto outgoing_app_cleanup;
09560 }
09561 if (synchronous) {
09562 chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
09563 if (chan) {
09564 ast_set_variables(chan, vars);
09565 if (account)
09566 ast_cdr_setaccount(chan, account);
09567 if (chan->_state == AST_STATE_UP) {
09568 res = 0;
09569 ast_verb(4, "Channel %s was answered.\n", chan->name);
09570 tmp = ast_calloc(1, sizeof(*tmp));
09571 if (!tmp || ast_string_field_init(tmp, 252)) {
09572 if (tmp) {
09573 ast_free(tmp);
09574 }
09575 res = -1;
09576 } else {
09577 ast_string_field_set(tmp, app, app);
09578 ast_string_field_set(tmp, data, appdata);
09579 tmp->chan = chan;
09580 if (synchronous > 1) {
09581 if (locked_channel)
09582 ast_channel_unlock(chan);
09583 ast_pbx_run_app(tmp);
09584 } else {
09585 if (locked_channel)
09586 ast_channel_lock(chan);
09587 if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
09588 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
09589 ast_string_field_free_memory(tmp);
09590 ast_free(tmp);
09591 if (locked_channel)
09592 ast_channel_unlock(chan);
09593 ast_hangup(chan);
09594 res = -1;
09595 } else {
09596 if (locked_channel)
09597 *locked_channel = chan;
09598 }
09599 }
09600 }
09601 } else {
09602 ast_verb(4, "Channel %s was never answered.\n", chan->name);
09603 if (chan->cdr) {
09604
09605
09606 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
09607 ast_cdr_failed(chan->cdr);
09608 }
09609 ast_hangup(chan);
09610 }
09611 }
09612
09613 if (res < 0) {
09614 if (*reason == 0) {
09615
09616 cdr_res = ast_pbx_outgoing_cdr_failed();
09617 if (cdr_res != 0) {
09618 res = cdr_res;
09619 goto outgoing_app_cleanup;
09620 }
09621 }
09622 }
09623
09624 } else {
09625 struct async_stat *as;
09626 if (!(as = ast_calloc(1, sizeof(*as)))) {
09627 res = -1;
09628 goto outgoing_app_cleanup;
09629 }
09630 chan = __ast_request_and_dial(type, format, NULL, data, timeout, reason, cid_num, cid_name, &oh);
09631 if (!chan) {
09632 ast_free(as);
09633 res = -1;
09634 goto outgoing_app_cleanup;
09635 }
09636 as->chan = chan;
09637 ast_copy_string(as->app, app, sizeof(as->app));
09638 if (appdata)
09639 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
09640 as->timeout = timeout;
09641 ast_set_variables(chan, vars);
09642 if (account)
09643 ast_cdr_setaccount(chan, account);
09644
09645 if (locked_channel)
09646 ast_channel_lock(chan);
09647 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
09648 ast_log(LOG_WARNING, "Failed to start async wait\n");
09649 ast_free(as);
09650 if (locked_channel)
09651 ast_channel_unlock(chan);
09652 ast_hangup(chan);
09653 res = -1;
09654 goto outgoing_app_cleanup;
09655 } else {
09656 if (locked_channel)
09657 *locked_channel = chan;
09658 }
09659 res = 0;
09660 }
09661 outgoing_app_cleanup:
09662 ast_variables_destroy(vars);
09663 return res;
09664 }
09665
09666
09667
09668
09669
09670 static void __ast_internal_context_destroy( struct ast_context *con)
09671 {
09672 struct ast_include *tmpi;
09673 struct ast_sw *sw;
09674 struct ast_exten *e, *el, *en;
09675 struct ast_ignorepat *ipi;
09676 struct ast_context *tmp = con;
09677
09678 for (tmpi = tmp->includes; tmpi; ) {
09679 struct ast_include *tmpil = tmpi;
09680 tmpi = tmpi->next;
09681 ast_free(tmpil);
09682 }
09683 for (ipi = tmp->ignorepats; ipi; ) {
09684 struct ast_ignorepat *ipl = ipi;
09685 ipi = ipi->next;
09686 ast_free(ipl);
09687 }
09688 if (tmp->registrar)
09689 ast_free(tmp->registrar);
09690
09691
09692 if (tmp->root_table) {
09693 ast_hashtab_destroy(tmp->root_table, 0);
09694 }
09695
09696 if (tmp->pattern_tree)
09697 destroy_pattern_tree(tmp->pattern_tree);
09698
09699 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
09700 ast_free(sw);
09701 for (e = tmp->root; e;) {
09702 for (en = e->peer; en;) {
09703 el = en;
09704 en = en->peer;
09705 destroy_exten(el);
09706 }
09707 el = e;
09708 e = e->next;
09709 destroy_exten(el);
09710 }
09711 tmp->root = NULL;
09712 ast_rwlock_destroy(&tmp->lock);
09713 ast_mutex_destroy(&tmp->macrolock);
09714 ast_free(tmp);
09715 }
09716
09717
09718 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
09719 {
09720 struct ast_context *tmp, *tmpl=NULL;
09721 struct ast_exten *exten_item, *prio_item;
09722
09723 for (tmp = list; tmp; ) {
09724 struct ast_context *next = NULL;
09725
09726
09727
09728
09729 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
09730 if (con) {
09731 for (; tmp; tmpl = tmp, tmp = tmp->next) {
09732 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
09733 if ( !strcasecmp(tmp->name, con->name) ) {
09734 break;
09735 }
09736 }
09737 }
09738
09739 if (!tmp)
09740 break;
09741 ast_wrlock_context(tmp);
09742
09743 if (registrar) {
09744
09745 struct ast_hashtab_iter *exten_iter;
09746 struct ast_hashtab_iter *prio_iter;
09747 struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
09748 struct ast_include *i, *pi = NULL, *ni = NULL;
09749 struct ast_sw *sw = NULL;
09750
09751
09752 for (ip = tmp->ignorepats; ip; ip = ipn) {
09753 ipn = ip->next;
09754 if (!strcmp(ip->registrar, registrar)) {
09755 if (ipl) {
09756 ipl->next = ip->next;
09757 ast_free(ip);
09758 continue;
09759 } else {
09760 tmp->ignorepats = ip->next;
09761 ast_free(ip);
09762 continue;
09763 }
09764 }
09765 ipl = ip;
09766 }
09767
09768 for (i = tmp->includes; i; i = ni) {
09769 ni = i->next;
09770 if (strcmp(i->registrar, registrar) == 0) {
09771
09772 if (pi) {
09773 pi->next = i->next;
09774
09775 ast_free(i);
09776 continue;
09777 } else {
09778 tmp->includes = i->next;
09779
09780 ast_free(i);
09781 continue;
09782 }
09783 }
09784 pi = i;
09785 }
09786
09787 AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
09788 if (strcmp(sw->registrar,registrar) == 0) {
09789 AST_LIST_REMOVE_CURRENT(list);
09790 ast_free(sw);
09791 }
09792 }
09793 AST_LIST_TRAVERSE_SAFE_END;
09794
09795 if (tmp->root_table) {
09796 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
09797 while ((exten_item=ast_hashtab_next(exten_iter))) {
09798 int end_traversal = 1;
09799 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
09800 while ((prio_item=ast_hashtab_next(prio_iter))) {
09801 char extension[AST_MAX_EXTENSION];
09802 char cidmatch[AST_MAX_EXTENSION];
09803 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
09804 continue;
09805 }
09806 ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
09807 tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
09808 ast_copy_string(extension, prio_item->exten, sizeof(extension));
09809 if (prio_item->cidmatch) {
09810 ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
09811 }
09812 end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
09813 }
09814
09815
09816
09817
09818
09819
09820
09821
09822 if (end_traversal) {
09823 ast_hashtab_end_traversal(prio_iter);
09824 } else {
09825 ast_free(prio_iter);
09826 }
09827 }
09828 ast_hashtab_end_traversal(exten_iter);
09829 }
09830
09831
09832
09833
09834 if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
09835 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
09836 ast_hashtab_remove_this_object(contexttab, tmp);
09837
09838 next = tmp->next;
09839 if (tmpl)
09840 tmpl->next = next;
09841 else
09842 contexts = next;
09843
09844
09845 ast_unlock_context(tmp);
09846 __ast_internal_context_destroy(tmp);
09847 } else {
09848 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
09849 tmp->refcount, tmp->root);
09850 ast_unlock_context(tmp);
09851 next = tmp->next;
09852 tmpl = tmp;
09853 }
09854 } else if (con) {
09855 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
09856 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
09857 ast_hashtab_remove_this_object(contexttab, tmp);
09858
09859 next = tmp->next;
09860 if (tmpl)
09861 tmpl->next = next;
09862 else
09863 contexts = next;
09864
09865
09866 ast_unlock_context(tmp);
09867 __ast_internal_context_destroy(tmp);
09868 }
09869
09870
09871 tmp = con ? NULL : next;
09872 }
09873 }
09874
09875 void ast_context_destroy(struct ast_context *con, const char *registrar)
09876 {
09877 ast_wrlock_contexts();
09878 __ast_context_destroy(contexts, contexts_table, con,registrar);
09879 ast_unlock_contexts();
09880 }
09881
09882 static void wait_for_hangup(struct ast_channel *chan, const void *data)
09883 {
09884 int res;
09885 struct ast_frame *f;
09886 double waitsec;
09887 int waittime;
09888
09889 if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
09890 waitsec = -1;
09891 if (waitsec > -1) {
09892 waittime = waitsec * 1000.0;
09893 ast_safe_sleep(chan, waittime);
09894 } else do {
09895 res = ast_waitfor(chan, -1);
09896 if (res < 0)
09897 return;
09898 f = ast_read(chan);
09899 if (f)
09900 ast_frfree(f);
09901 } while(f);
09902 }
09903
09904
09905
09906
09907 static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
09908 {
09909 ast_indicate(chan, AST_CONTROL_PROCEEDING);
09910 return 0;
09911 }
09912
09913
09914
09915
09916 static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
09917 {
09918 ast_indicate(chan, AST_CONTROL_PROGRESS);
09919 return 0;
09920 }
09921
09922
09923
09924
09925 static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
09926 {
09927 ast_indicate(chan, AST_CONTROL_RINGING);
09928 return 0;
09929 }
09930
09931
09932
09933
09934 static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
09935 {
09936 ast_indicate(chan, AST_CONTROL_BUSY);
09937
09938
09939 if (chan->_state != AST_STATE_UP) {
09940 ast_setstate(chan, AST_STATE_BUSY);
09941 ast_cdr_busy(chan->cdr);
09942 }
09943 wait_for_hangup(chan, data);
09944 return -1;
09945 }
09946
09947
09948
09949
09950 static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
09951 {
09952 ast_indicate(chan, AST_CONTROL_CONGESTION);
09953
09954
09955 if (chan->_state != AST_STATE_UP)
09956 ast_setstate(chan, AST_STATE_BUSY);
09957 wait_for_hangup(chan, data);
09958 return -1;
09959 }
09960
09961
09962
09963
09964 static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
09965 {
09966 int delay = 0;
09967 int answer_cdr = 1;
09968 char *parse;
09969 AST_DECLARE_APP_ARGS(args,
09970 AST_APP_ARG(delay);
09971 AST_APP_ARG(answer_cdr);
09972 );
09973
09974 if (ast_strlen_zero(data)) {
09975 return __ast_answer(chan, 0, 1);
09976 }
09977
09978 parse = ast_strdupa(data);
09979
09980 AST_STANDARD_APP_ARGS(args, parse);
09981
09982 if (!ast_strlen_zero(args.delay) && (chan->_state != AST_STATE_UP))
09983 delay = atoi(data);
09984
09985 if (delay < 0) {
09986 delay = 0;
09987 }
09988
09989 if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
09990 answer_cdr = 0;
09991 }
09992
09993 return __ast_answer(chan, delay, answer_cdr);
09994 }
09995
09996 static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
09997 {
09998 const char *options = data;
09999 int answer = 1;
10000
10001
10002 if (!ast_strlen_zero(options) && strchr(options, 'n')) {
10003 answer = 0;
10004 }
10005
10006
10007 if (ast_check_hangup(chan)) {
10008 return -1;
10009 } else if (chan->_state != AST_STATE_UP && answer) {
10010 __ast_answer(chan, 0, 1);
10011 }
10012
10013 ast_indicate(chan, AST_CONTROL_INCOMPLETE);
10014
10015 return AST_PBX_INCOMPLETE;
10016 }
10017
10018 AST_APP_OPTIONS(resetcdr_opts, {
10019 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
10020 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
10021 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
10022 AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),
10023 });
10024
10025
10026
10027
10028 static int pbx_builtin_resetcdr(struct ast_channel *chan, const char *data)
10029 {
10030 char *args;
10031 struct ast_flags flags = { 0 };
10032
10033 if (!ast_strlen_zero(data)) {
10034 args = ast_strdupa(data);
10035 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
10036 }
10037
10038 ast_cdr_reset(chan->cdr, &flags);
10039
10040 return 0;
10041 }
10042
10043
10044
10045
10046 static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
10047 {
10048
10049 ast_channel_lock(chan);
10050 ast_cdr_setamaflags(chan, data ? data : "");
10051 ast_channel_unlock(chan);
10052 return 0;
10053 }
10054
10055
10056
10057
10058 static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
10059 {
10060 ast_set_hangupsource(chan, "dialplan/builtin", 0);
10061
10062 if (!ast_strlen_zero(data)) {
10063 int cause;
10064 char *endptr;
10065
10066 if ((cause = ast_str2cause(data)) > -1) {
10067 chan->hangupcause = cause;
10068 return -1;
10069 }
10070
10071 cause = strtol((const char *) data, &endptr, 10);
10072 if (cause != 0 || (data != endptr)) {
10073 chan->hangupcause = cause;
10074 return -1;
10075 }
10076
10077 ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
10078 }
10079
10080 if (!chan->hangupcause) {
10081 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
10082 }
10083
10084 return -1;
10085 }
10086
10087
10088
10089
10090 static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
10091 {
10092 struct ast_tm tm;
10093 struct timeval tv;
10094 char *remainder, result[30], timezone[80];
10095
10096
10097 if (!pbx_checkcondition(value)) {
10098 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
10099 return 0;
10100 }
10101
10102
10103 if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
10104 return -1;
10105 }
10106 sscanf(remainder, "%79s", timezone);
10107 tv = ast_mktime(&tm, S_OR(timezone, NULL));
10108
10109 snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
10110 pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
10111 return 0;
10112 }
10113
10114 static struct ast_custom_function testtime_function = {
10115 .name = "TESTTIME",
10116 .write = testtime_write,
10117 };
10118
10119
10120
10121
10122 static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
10123 {
10124 char *s, *ts, *branch1, *branch2, *branch;
10125 struct ast_timing timing;
10126 const char *ctime;
10127 struct timeval tv = ast_tvnow();
10128 long timesecs;
10129
10130 if (!chan) {
10131 ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n");
10132 return -1;
10133 }
10134
10135 if (ast_strlen_zero(data)) {
10136 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
10137 return -1;
10138 }
10139
10140 ts = s = ast_strdupa(data);
10141
10142 ast_channel_lock(chan);
10143 if ((ctime = pbx_builtin_getvar_helper(chan, "TESTTIME")) && sscanf(ctime, "%ld", ×ecs) == 1) {
10144 tv.tv_sec = timesecs;
10145 } else if (ctime) {
10146 ast_log(LOG_WARNING, "Using current time to evaluate\n");
10147
10148 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
10149 }
10150 ast_channel_unlock(chan);
10151
10152
10153 strsep(&ts, "?");
10154 branch1 = strsep(&ts,":");
10155 branch2 = strsep(&ts,"");
10156
10157
10158 if (ast_build_timing(&timing, s) && ast_check_timing2(&timing, tv)) {
10159 branch = branch1;
10160 } else {
10161 branch = branch2;
10162 }
10163 ast_destroy_timing(&timing);
10164
10165 if (ast_strlen_zero(branch)) {
10166 ast_debug(1, "Not taking any branch\n");
10167 return 0;
10168 }
10169
10170 return pbx_builtin_goto(chan, branch);
10171 }
10172
10173
10174
10175
10176 static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
10177 {
10178 char *s, *appname;
10179 struct ast_timing timing;
10180 struct ast_app *app;
10181 static const char * const usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
10182
10183 if (ast_strlen_zero(data)) {
10184 ast_log(LOG_WARNING, "%s\n", usage);
10185 return -1;
10186 }
10187
10188 appname = ast_strdupa(data);
10189
10190 s = strsep(&appname, "?");
10191 if (!appname) {
10192 ast_log(LOG_WARNING, "%s\n", usage);
10193 return -1;
10194 }
10195
10196 if (!ast_build_timing(&timing, s)) {
10197 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
10198 ast_destroy_timing(&timing);
10199 return -1;
10200 }
10201
10202 if (!ast_check_timing(&timing)) {
10203 ast_destroy_timing(&timing);
10204 return 0;
10205 }
10206 ast_destroy_timing(&timing);
10207
10208
10209 if ((s = strchr(appname, '('))) {
10210 char *e;
10211 *s++ = '\0';
10212 if ((e = strrchr(s, ')')))
10213 *e = '\0';
10214 else
10215 ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
10216 }
10217
10218
10219 if ((app = pbx_findapp(appname))) {
10220 return pbx_exec(chan, app, S_OR(s, ""));
10221 } else {
10222 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
10223 return -1;
10224 }
10225 }
10226
10227
10228
10229
10230 static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
10231 {
10232 int ms;
10233
10234
10235 if (!ast_app_parse_timelen(data, &ms, TIMELEN_SECONDS) && ms > 0) {
10236 return ast_safe_sleep(chan, ms);
10237 }
10238 return 0;
10239 }
10240
10241
10242
10243
10244 static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
10245 {
10246 int ms, res;
10247 struct ast_flags flags = {0};
10248 char *opts[1] = { NULL };
10249 char *parse;
10250 AST_DECLARE_APP_ARGS(args,
10251 AST_APP_ARG(timeout);
10252 AST_APP_ARG(options);
10253 );
10254
10255 if (!ast_strlen_zero(data)) {
10256 parse = ast_strdupa(data);
10257 AST_STANDARD_APP_ARGS(args, parse);
10258 } else
10259 memset(&args, 0, sizeof(args));
10260
10261 if (args.options)
10262 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
10263
10264 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
10265 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
10266 } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
10267 ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL),
10268 !ast_strlen_zero(opts[0]) ? strlen(opts[0]) + 1 : 0);
10269 } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
10270 struct ast_tone_zone_sound *ts = ast_get_indication_tone(chan->zone, "dial");
10271 if (ts) {
10272 ast_playtones_start(chan, 0, ts->data, 0);
10273 ts = ast_tone_zone_sound_unref(ts);
10274 } else {
10275 ast_tonepair_start(chan, 350, 440, 0, 0);
10276 }
10277 }
10278
10279 if (!ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) && ms > 0) {
10280
10281 } else if (chan->pbx) {
10282 ms = chan->pbx->rtimeoutms;
10283 } else {
10284 ms = 10000;
10285 }
10286
10287 res = ast_waitfordigit(chan, ms);
10288 if (!res) {
10289 if (ast_check_hangup(chan)) {
10290
10291 res = -1;
10292 } else if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1,
10293 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
10294 ast_verb(3, "Timeout on %s, continuing...\n", chan->name);
10295 } else if (ast_exists_extension(chan, chan->context, "t", 1,
10296 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
10297 ast_verb(3, "Timeout on %s, going to 't'\n", chan->name);
10298 set_ext_pri(chan, "t", 0);
10299 } else if (ast_exists_extension(chan, chan->context, "e", 1,
10300 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
10301 raise_exception(chan, "RESPONSETIMEOUT", 0);
10302 } else {
10303 ast_log(LOG_WARNING, "Timeout but no rule 't' or 'e' in context '%s'\n",
10304 chan->context);
10305 res = -1;
10306 }
10307 }
10308
10309 if (ast_test_flag(&flags, WAITEXTEN_MOH))
10310 ast_indicate(chan, AST_CONTROL_UNHOLD);
10311 else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
10312 ast_playtones_stop(chan);
10313
10314 return res;
10315 }
10316
10317
10318
10319
10320 static int pbx_builtin_background(struct ast_channel *chan, const char *data)
10321 {
10322 int res = 0;
10323 int mres = 0;
10324 struct ast_flags flags = {0};
10325 char *parse, exten[2] = "";
10326 AST_DECLARE_APP_ARGS(args,
10327 AST_APP_ARG(filename);
10328 AST_APP_ARG(options);
10329 AST_APP_ARG(lang);
10330 AST_APP_ARG(context);
10331 );
10332
10333 if (ast_strlen_zero(data)) {
10334 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
10335 return -1;
10336 }
10337
10338 parse = ast_strdupa(data);
10339
10340 AST_STANDARD_APP_ARGS(args, parse);
10341
10342 if (ast_strlen_zero(args.lang))
10343 args.lang = (char *)chan->language;
10344
10345 if (ast_strlen_zero(args.context)) {
10346 const char *context;
10347 ast_channel_lock(chan);
10348 if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
10349 args.context = ast_strdupa(context);
10350 } else {
10351 args.context = chan->context;
10352 }
10353 ast_channel_unlock(chan);
10354 }
10355
10356 if (args.options) {
10357 if (!strcasecmp(args.options, "skip"))
10358 flags.flags = BACKGROUND_SKIP;
10359 else if (!strcasecmp(args.options, "noanswer"))
10360 flags.flags = BACKGROUND_NOANSWER;
10361 else
10362 ast_app_parse_options(background_opts, &flags, NULL, args.options);
10363 }
10364
10365
10366 if (chan->_state != AST_STATE_UP) {
10367 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
10368 goto done;
10369 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
10370 res = ast_answer(chan);
10371 }
10372 }
10373
10374 if (!res) {
10375 char *back = ast_strip(args.filename);
10376 char *front;
10377
10378 ast_stopstream(chan);
10379
10380 while (!res && (front = strsep(&back, "&")) ) {
10381 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
10382 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
10383 res = 0;
10384 mres = 1;
10385 break;
10386 }
10387 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
10388 res = ast_waitstream(chan, "");
10389 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
10390 res = ast_waitstream_exten(chan, args.context);
10391 } else {
10392 res = ast_waitstream(chan, AST_DIGIT_ANY);
10393 }
10394 ast_stopstream(chan);
10395 }
10396 }
10397
10398
10399
10400
10401
10402
10403
10404
10405
10406
10407
10408
10409
10410
10411
10412
10413
10414
10415
10416 if (!ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS)
10417 && (exten[0] = res)
10418 && ast_canmatch_extension(chan, args.context, exten, 1,
10419 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))
10420 && !ast_matchmore_extension(chan, args.context, exten, 1,
10421 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
10422 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
10423 ast_copy_string(chan->context, args.context, sizeof(chan->context));
10424 chan->priority = 0;
10425 res = 0;
10426 }
10427 done:
10428 pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
10429 return res;
10430 }
10431
10432
10433
10434
10435 static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
10436 {
10437 int res = ast_parseable_goto(chan, data);
10438 if (!res)
10439 ast_verb(3, "Goto (%s,%s,%d)\n", chan->context, chan->exten, chan->priority + 1);
10440 return res;
10441 }
10442
10443
10444 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
10445 {
10446 struct ast_var_t *variables;
10447 const char *var, *val;
10448 int total = 0;
10449
10450 if (!chan)
10451 return 0;
10452
10453 ast_str_reset(*buf);
10454
10455 ast_channel_lock(chan);
10456
10457 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
10458 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
10459
10460 ) {
10461 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
10462 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
10463 break;
10464 } else
10465 total++;
10466 } else
10467 break;
10468 }
10469
10470 ast_channel_unlock(chan);
10471
10472 return total;
10473 }
10474
10475 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
10476 {
10477 struct ast_var_t *variables;
10478 const char *ret = NULL;
10479 int i;
10480 struct varshead *places[2] = { NULL, &globals };
10481
10482 if (!name)
10483 return NULL;
10484
10485 if (chan) {
10486 ast_channel_lock(chan);
10487 places[0] = &chan->varshead;
10488 }
10489
10490 for (i = 0; i < 2; i++) {
10491 if (!places[i])
10492 continue;
10493 if (places[i] == &globals)
10494 ast_rwlock_rdlock(&globalslock);
10495 AST_LIST_TRAVERSE(places[i], variables, entries) {
10496 if (!strcmp(name, ast_var_name(variables))) {
10497 ret = ast_var_value(variables);
10498 break;
10499 }
10500 }
10501 if (places[i] == &globals)
10502 ast_rwlock_unlock(&globalslock);
10503 if (ret)
10504 break;
10505 }
10506
10507 if (chan)
10508 ast_channel_unlock(chan);
10509
10510 return ret;
10511 }
10512
10513 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
10514 {
10515 struct ast_var_t *newvariable;
10516 struct varshead *headp;
10517
10518 if (name[strlen(name)-1] == ')') {
10519 char *function = ast_strdupa(name);
10520
10521 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
10522 ast_func_write(chan, function, value);
10523 return;
10524 }
10525
10526 if (chan) {
10527 ast_channel_lock(chan);
10528 headp = &chan->varshead;
10529 } else {
10530 ast_rwlock_wrlock(&globalslock);
10531 headp = &globals;
10532 }
10533
10534 if (value && (newvariable = ast_var_assign(name, value))) {
10535 if (headp == &globals)
10536 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
10537 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
10538 }
10539
10540 if (chan)
10541 ast_channel_unlock(chan);
10542 else
10543 ast_rwlock_unlock(&globalslock);
10544 }
10545
10546 int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
10547 {
10548 struct ast_var_t *newvariable;
10549 struct varshead *headp;
10550 const char *nametail = name;
10551
10552 if (name[strlen(name) - 1] == ')') {
10553 char *function = ast_strdupa(name);
10554
10555 return ast_func_write(chan, function, value);
10556 }
10557
10558 if (chan) {
10559 ast_channel_lock(chan);
10560 headp = &chan->varshead;
10561 } else {
10562 ast_rwlock_wrlock(&globalslock);
10563 headp = &globals;
10564 }
10565
10566
10567 if (*nametail == '_') {
10568 nametail++;
10569 if (*nametail == '_')
10570 nametail++;
10571 }
10572
10573 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
10574 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
10575
10576 AST_LIST_REMOVE_CURRENT(entries);
10577 ast_var_delete(newvariable);
10578 break;
10579 }
10580 }
10581 AST_LIST_TRAVERSE_SAFE_END;
10582
10583 if (value && (newvariable = ast_var_assign(name, value))) {
10584 if (headp == &globals)
10585 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
10586 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
10587 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
10588 "Channel: %s\r\n"
10589 "Variable: %s\r\n"
10590 "Value: %s\r\n"
10591 "Uniqueid: %s\r\n",
10592 chan ? chan->name : "none", name, value,
10593 chan ? chan->uniqueid : "none");
10594 }
10595
10596 if (chan)
10597 ast_channel_unlock(chan);
10598 else
10599 ast_rwlock_unlock(&globalslock);
10600 return 0;
10601 }
10602
10603 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
10604 {
10605 char *name, *value, *mydata;
10606
10607 if (ast_compat_app_set) {
10608 return pbx_builtin_setvar_multiple(chan, data);
10609 }
10610
10611 if (ast_strlen_zero(data)) {
10612 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
10613 return 0;
10614 }
10615
10616 mydata = ast_strdupa(data);
10617 name = strsep(&mydata, "=");
10618 value = mydata;
10619 if (!value) {
10620 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
10621 return 0;
10622 }
10623
10624 if (strchr(name, ' ')) {
10625 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
10626 }
10627
10628 pbx_builtin_setvar_helper(chan, name, value);
10629
10630 return 0;
10631 }
10632
10633 int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
10634 {
10635 char *data;
10636 int x;
10637 AST_DECLARE_APP_ARGS(args,
10638 AST_APP_ARG(pair)[24];
10639 );
10640 AST_DECLARE_APP_ARGS(pair,
10641 AST_APP_ARG(name);
10642 AST_APP_ARG(value);
10643 );
10644
10645 if (ast_strlen_zero(vdata)) {
10646 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
10647 return 0;
10648 }
10649
10650 data = ast_strdupa(vdata);
10651 AST_STANDARD_APP_ARGS(args, data);
10652
10653 for (x = 0; x < args.argc; x++) {
10654 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
10655 if (pair.argc == 2) {
10656 pbx_builtin_setvar_helper(chan, pair.name, pair.value);
10657 if (strchr(pair.name, ' '))
10658 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
10659 } else if (!chan) {
10660 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
10661 } else {
10662 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
10663 }
10664 }
10665
10666 return 0;
10667 }
10668
10669 int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
10670 {
10671 char *name;
10672 char *value;
10673 char *channel;
10674 char tmp[VAR_BUF_SIZE];
10675 static int deprecation_warning = 0;
10676
10677 if (ast_strlen_zero(data)) {
10678 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
10679 return 0;
10680 }
10681 tmp[0] = 0;
10682 if (!deprecation_warning) {
10683 ast_log(LOG_WARNING, "ImportVar is deprecated. Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
10684 deprecation_warning = 1;
10685 }
10686
10687 value = ast_strdupa(data);
10688 name = strsep(&value,"=");
10689 channel = strsep(&value,",");
10690 if (channel && value && name) {
10691 struct ast_channel *chan2 = ast_channel_get_by_name(channel);
10692 if (chan2) {
10693 char *s = ast_alloca(strlen(value) + 4);
10694 sprintf(s, "${%s}", value);
10695 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
10696 chan2 = ast_channel_unref(chan2);
10697 }
10698 pbx_builtin_setvar_helper(chan, name, tmp);
10699 }
10700
10701 return(0);
10702 }
10703
10704 static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
10705 {
10706 return 0;
10707 }
10708
10709 void pbx_builtin_clear_globals(void)
10710 {
10711 struct ast_var_t *vardata;
10712
10713 ast_rwlock_wrlock(&globalslock);
10714 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
10715 ast_var_delete(vardata);
10716 ast_rwlock_unlock(&globalslock);
10717 }
10718
10719 int pbx_checkcondition(const char *condition)
10720 {
10721 int res;
10722 if (ast_strlen_zero(condition)) {
10723 return 0;
10724 } else if (sscanf(condition, "%30d", &res) == 1) {
10725 return res;
10726 } else {
10727 return 1;
10728 }
10729 }
10730
10731 static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
10732 {
10733 char *condition, *branch1, *branch2, *branch;
10734 char *stringp;
10735
10736 if (ast_strlen_zero(data)) {
10737 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
10738 return 0;
10739 }
10740
10741 stringp = ast_strdupa(data);
10742 condition = strsep(&stringp,"?");
10743 branch1 = strsep(&stringp,":");
10744 branch2 = strsep(&stringp,"");
10745 branch = pbx_checkcondition(condition) ? branch1 : branch2;
10746
10747 if (ast_strlen_zero(branch)) {
10748 ast_debug(1, "Not taking any branch\n");
10749 return 0;
10750 }
10751
10752 return pbx_builtin_goto(chan, branch);
10753 }
10754
10755 static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
10756 {
10757 char tmp[256];
10758 char *number = tmp;
10759 char *options;
10760
10761 if (ast_strlen_zero(data)) {
10762 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
10763 return -1;
10764 }
10765 ast_copy_string(tmp, data, sizeof(tmp));
10766 strsep(&number, ",");
10767 options = strsep(&number, ",");
10768 if (options) {
10769 if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
10770 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
10771 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
10772 return -1;
10773 }
10774 }
10775
10776 if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
10777 ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
10778 }
10779
10780 return 0;
10781 }
10782
10783 static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
10784 {
10785 int res = 0;
10786
10787 if (data)
10788 res = ast_say_digit_str(chan, data, "", chan->language);
10789 return res;
10790 }
10791
10792 static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
10793 {
10794 int res = 0;
10795
10796 if (data)
10797 res = ast_say_character_str(chan, data, "", chan->language);
10798 return res;
10799 }
10800
10801 static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
10802 {
10803 int res = 0;
10804
10805 if (data)
10806 res = ast_say_phonetic_str(chan, data, "", chan->language);
10807 return res;
10808 }
10809
10810 static int pbx_builtin_saydate(struct ast_channel *chan, const char *data)
10811 {
10812 int res = 0;
10813 char *parse;
10814 int unixdate = 0;
10815 char charascii[2];
10816
10817 AST_DECLARE_APP_ARGS(args,
10818 AST_APP_ARG(datestr);
10819 AST_APP_ARG(digits);
10820 );
10821
10822
10823 if (ast_strlen_zero(data)) {
10824 ast_log(LOG_WARNING, "SayDate requires an argument (date)\n");
10825 return -1;
10826 }
10827
10828 if (!(parse = ast_strdupa(data))) {
10829 ast_log(LOG_WARNING, "Memory Error!\n");
10830 return -1;
10831 }
10832
10833 AST_STANDARD_APP_ARGS(args, parse);
10834
10835 if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
10836 ast_log(LOG_WARNING, "SayDate escape digits must be a subset from '0123456789*#'\n");
10837 args.digits = "";
10838 }
10839
10840 if (sscanf(args.datestr, "%d", &unixdate) != 1) {
10841 ast_log(LOG_WARNING, "Firt argument to SayDate must be numeric (date)\n");
10842 return -1;
10843 }
10844
10845 res = ast_say_date(chan, (time_t)unixdate, args.digits, chan->language);
10846 if (res > 0) {
10847 if (isdigit(res) || (res == '*') || (res == '#')) {
10848 snprintf(charascii, 2, "%c", res);
10849 pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
10850 res = 0;
10851 } else {
10852 ast_log(LOG_WARNING, "SayDate: invalid return value (%d) detected\n", res);
10853 }
10854 }
10855 return res;
10856 }
10857
10858 static int pbx_builtin_saytime(struct ast_channel *chan, const char *data)
10859 {
10860 int res = 0;
10861 char *parse;
10862 int secs = 0;
10863 char charascii[2];
10864
10865 AST_DECLARE_APP_ARGS(args,
10866 AST_APP_ARG(timestr);
10867 AST_APP_ARG(digits);
10868 );
10869
10870 if (ast_strlen_zero(data)) {
10871 ast_log(LOG_WARNING, "SayTime requires an argument (time in seconds)\n");
10872 return -1;
10873 }
10874
10875 if (!(parse = ast_strdupa(data))) {
10876 ast_log(LOG_WARNING, "Memory Error!\n");
10877 return -1;
10878 }
10879
10880 AST_STANDARD_APP_ARGS(args, parse);
10881
10882 if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
10883 ast_log(LOG_WARNING, "SayTime escape digits must be a subset from '0123456789*#'\n");
10884 args.digits = "";
10885 }
10886
10887 if (sscanf(args.timestr, "%d", &secs) != 1) {
10888 ast_log(LOG_WARNING, "Firt argument to SayTime must be numeric (time in seconds)\n");
10889 return -1;
10890 }
10891
10892 res = ast_say_time(chan, (time_t)secs, args.digits, chan->language);
10893 if (res > 0) {
10894 if (isdigit(res) || (res == '*') || (res == '#')) {
10895 snprintf(charascii, 2, "%c", res);
10896 pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
10897 res = 0;
10898 } else {
10899 ast_log(LOG_WARNING, "SayTime: invalid return value (%d) detected\n", res);
10900 }
10901 }
10902 return res;
10903 }
10904
10905 static void device_state_cb(const struct ast_event *event, void *unused)
10906 {
10907 const char *device;
10908 struct statechange *sc;
10909
10910 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
10911 if (ast_strlen_zero(device)) {
10912 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
10913 return;
10914 }
10915
10916 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
10917 return;
10918 strcpy(sc->dev, device);
10919 if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
10920 ast_free(sc);
10921 }
10922 }
10923
10924
10925
10926
10927
10928 static int hints_data_provider_get(const struct ast_data_search *search,
10929 struct ast_data *data_root)
10930 {
10931 struct ast_data *data_hint;
10932 struct ast_hint *hint;
10933 int watchers;
10934 struct ao2_iterator i;
10935
10936 if (ao2_container_count(hints) == 0) {
10937 return 0;
10938 }
10939
10940 i = ao2_iterator_init(hints, 0);
10941 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
10942 watchers = ao2_container_count(hint->callbacks);
10943 data_hint = ast_data_add_node(data_root, "hint");
10944 if (!data_hint) {
10945 continue;
10946 }
10947 ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten));
10948 ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
10949 ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
10950 ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
10951 ast_data_add_int(data_hint, "watchers", watchers);
10952
10953 if (!ast_data_search_match(search, data_hint)) {
10954 ast_data_remove_node(data_root, data_hint);
10955 }
10956 }
10957 ao2_iterator_destroy(&i);
10958
10959 return 0;
10960 }
10961
10962 static const struct ast_data_handler hints_data_provider = {
10963 .version = AST_DATA_HANDLER_VERSION,
10964 .get = hints_data_provider_get
10965 };
10966
10967 static const struct ast_data_entry pbx_data_providers[] = {
10968 AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
10969 };
10970
10971
10972
10973 static void unload_pbx(void)
10974 {
10975 int x;
10976
10977 if (device_state_sub) {
10978 device_state_sub = ast_event_unsubscribe(device_state_sub);
10979 }
10980 if (device_state_tps) {
10981 ast_taskprocessor_unreference(device_state_tps);
10982 device_state_tps = NULL;
10983 }
10984
10985
10986 for (x = 0; x < ARRAY_LEN(builtins); x++) {
10987 ast_unregister_application(builtins[x].name);
10988 }
10989 ast_manager_unregister("ShowDialPlan");
10990 ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
10991 ast_custom_function_unregister(&exception_function);
10992 ast_custom_function_unregister(&testtime_function);
10993 ast_data_unregister(NULL);
10994 }
10995
10996 int load_pbx(void)
10997 {
10998 int x;
10999
11000 ast_register_atexit(unload_pbx);
11001
11002
11003 ast_verb(1, "Asterisk PBX Core Initializing\n");
11004 if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
11005 ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
11006 }
11007
11008 ast_verb(1, "Registering builtin applications:\n");
11009 ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
11010 ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
11011 __ast_custom_function_register(&exception_function, NULL);
11012 __ast_custom_function_register(&testtime_function, NULL);
11013
11014
11015 for (x = 0; x < ARRAY_LEN(builtins); x++) {
11016 ast_verb(1, "[%s]\n", builtins[x].name);
11017 if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
11018 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
11019 return -1;
11020 }
11021 }
11022
11023
11024 ast_manager_register_xml("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
11025
11026 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "pbx Device State Change", NULL,
11027 AST_EVENT_IE_END))) {
11028 return -1;
11029 }
11030
11031 return 0;
11032 }
11033
11034
11035
11036
11037 int ast_wrlock_contexts(void)
11038 {
11039 return ast_mutex_lock(&conlock);
11040 }
11041
11042 int ast_rdlock_contexts(void)
11043 {
11044 return ast_mutex_lock(&conlock);
11045 }
11046
11047 int ast_unlock_contexts(void)
11048 {
11049 return ast_mutex_unlock(&conlock);
11050 }
11051
11052
11053
11054
11055 int ast_wrlock_context(struct ast_context *con)
11056 {
11057 return ast_rwlock_wrlock(&con->lock);
11058 }
11059
11060 int ast_rdlock_context(struct ast_context *con)
11061 {
11062 return ast_rwlock_rdlock(&con->lock);
11063 }
11064
11065 int ast_unlock_context(struct ast_context *con)
11066 {
11067 return ast_rwlock_unlock(&con->lock);
11068 }
11069
11070
11071
11072
11073 const char *ast_get_context_name(struct ast_context *con)
11074 {
11075 return con ? con->name : NULL;
11076 }
11077
11078 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
11079 {
11080 return exten ? exten->parent : NULL;
11081 }
11082
11083 const char *ast_get_extension_name(struct ast_exten *exten)
11084 {
11085 return exten ? exten->exten : NULL;
11086 }
11087
11088 const char *ast_get_extension_label(struct ast_exten *exten)
11089 {
11090 return exten ? exten->label : NULL;
11091 }
11092
11093 const char *ast_get_include_name(struct ast_include *inc)
11094 {
11095 return inc ? inc->name : NULL;
11096 }
11097
11098 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
11099 {
11100 return ip ? ip->pattern : NULL;
11101 }
11102
11103 int ast_get_extension_priority(struct ast_exten *exten)
11104 {
11105 return exten ? exten->priority : -1;
11106 }
11107
11108
11109
11110
11111 const char *ast_get_context_registrar(struct ast_context *c)
11112 {
11113 return c ? c->registrar : NULL;
11114 }
11115
11116 const char *ast_get_extension_registrar(struct ast_exten *e)
11117 {
11118 return e ? e->registrar : NULL;
11119 }
11120
11121 const char *ast_get_include_registrar(struct ast_include *i)
11122 {
11123 return i ? i->registrar : NULL;
11124 }
11125
11126 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
11127 {
11128 return ip ? ip->registrar : NULL;
11129 }
11130
11131 int ast_get_extension_matchcid(struct ast_exten *e)
11132 {
11133 return e ? e->matchcid : 0;
11134 }
11135
11136 const char *ast_get_extension_cidmatch(struct ast_exten *e)
11137 {
11138 return e ? e->cidmatch : NULL;
11139 }
11140
11141 const char *ast_get_extension_app(struct ast_exten *e)
11142 {
11143 return e ? e->app : NULL;
11144 }
11145
11146 void *ast_get_extension_app_data(struct ast_exten *e)
11147 {
11148 return e ? e->data : NULL;
11149 }
11150
11151 const char *ast_get_switch_name(struct ast_sw *sw)
11152 {
11153 return sw ? sw->name : NULL;
11154 }
11155
11156 const char *ast_get_switch_data(struct ast_sw *sw)
11157 {
11158 return sw ? sw->data : NULL;
11159 }
11160
11161 int ast_get_switch_eval(struct ast_sw *sw)
11162 {
11163 return sw->eval;
11164 }
11165
11166 const char *ast_get_switch_registrar(struct ast_sw *sw)
11167 {
11168 return sw ? sw->registrar : NULL;
11169 }
11170
11171
11172
11173
11174 struct ast_context *ast_walk_contexts(struct ast_context *con)
11175 {
11176 return con ? con->next : contexts;
11177 }
11178
11179 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
11180 struct ast_exten *exten)
11181 {
11182 if (!exten)
11183 return con ? con->root : NULL;
11184 else
11185 return exten->next;
11186 }
11187
11188 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
11189 struct ast_sw *sw)
11190 {
11191 if (!sw)
11192 return con ? AST_LIST_FIRST(&con->alts) : NULL;
11193 else
11194 return AST_LIST_NEXT(sw, list);
11195 }
11196
11197 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
11198 struct ast_exten *priority)
11199 {
11200 return priority ? priority->peer : exten;
11201 }
11202
11203 struct ast_include *ast_walk_context_includes(struct ast_context *con,
11204 struct ast_include *inc)
11205 {
11206 if (!inc)
11207 return con ? con->includes : NULL;
11208 else
11209 return inc->next;
11210 }
11211
11212 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
11213 struct ast_ignorepat *ip)
11214 {
11215 if (!ip)
11216 return con ? con->ignorepats : NULL;
11217 else
11218 return ip->next;
11219 }
11220
11221 int ast_context_verify_includes(struct ast_context *con)
11222 {
11223 struct ast_include *inc = NULL;
11224 int res = 0;
11225
11226 while ( (inc = ast_walk_context_includes(con, inc)) ) {
11227 if (ast_context_find(inc->rname))
11228 continue;
11229
11230 res = -1;
11231 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
11232 ast_get_context_name(con), inc->rname);
11233 break;
11234 }
11235
11236 return res;
11237 }
11238
11239
11240 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
11241 {
11242 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
11243
11244 if (!chan)
11245 return -2;
11246
11247 if (context == NULL)
11248 context = chan->context;
11249 if (exten == NULL)
11250 exten = chan->exten;
11251
11252 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
11253 if (ast_exists_extension(chan, context, exten, priority,
11254 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)))
11255 return goto_func(chan, context, exten, priority);
11256 else {
11257 return AST_PBX_GOTO_FAILED;
11258 }
11259 }
11260
11261 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
11262 {
11263 return __ast_goto_if_exists(chan, context, exten, priority, 0);
11264 }
11265
11266 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
11267 {
11268 return __ast_goto_if_exists(chan, context, exten, priority, 1);
11269 }
11270
11271 static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
11272 {
11273 char *exten, *pri, *context;
11274 char *stringp;
11275 int ipri;
11276 int mode = 0;
11277
11278 if (ast_strlen_zero(goto_string)) {
11279 ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
11280 return -1;
11281 }
11282 stringp = ast_strdupa(goto_string);
11283 context = strsep(&stringp, ",");
11284 exten = strsep(&stringp, ",");
11285 pri = strsep(&stringp, ",");
11286 if (!exten) {
11287 pri = context;
11288 exten = NULL;
11289 context = NULL;
11290 } else if (!pri) {
11291 pri = exten;
11292 exten = context;
11293 context = NULL;
11294 }
11295 if (*pri == '+') {
11296 mode = 1;
11297 pri++;
11298 } else if (*pri == '-') {
11299 mode = -1;
11300 pri++;
11301 }
11302 if (sscanf(pri, "%30d", &ipri) != 1) {
11303 ipri = ast_findlabel_extension(chan, context ? context : chan->context,
11304 exten ? exten : chan->exten, pri,
11305 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
11306 if (ipri < 1) {
11307 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
11308 return -1;
11309 } else
11310 mode = 0;
11311 }
11312
11313
11314 if (mode)
11315 ipri = chan->priority + (ipri * mode);
11316
11317 if (async)
11318 ast_async_goto(chan, context, exten, ipri);
11319 else
11320 ast_explicit_goto(chan, context, exten, ipri);
11321
11322 return 0;
11323
11324 }
11325
11326 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
11327 {
11328 return pbx_parseable_goto(chan, goto_string, 0);
11329 }
11330
11331 int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
11332 {
11333 return pbx_parseable_goto(chan, goto_string, 1);
11334 }
11335
11336 char *ast_complete_applications(const char *line, const char *word, int state)
11337 {
11338 struct ast_app *app = NULL;
11339 int which = 0;
11340 char *ret = NULL;
11341 size_t wordlen = strlen(word);
11342
11343 AST_RWLIST_RDLOCK(&apps);
11344 AST_RWLIST_TRAVERSE(&apps, app, list) {
11345 if (!strncasecmp(word, app->name, wordlen) && ++which > state) {
11346 ret = ast_strdup(app->name);
11347 break;
11348 }
11349 }
11350 AST_RWLIST_UNLOCK(&apps);
11351
11352 return ret;
11353 }
11354
11355 static int hint_hash(const void *obj, const int flags)
11356 {
11357 const struct ast_hint *hint = obj;
11358 const char *exten_name;
11359 int res;
11360
11361 exten_name = ast_get_extension_name(hint->exten);
11362 if (ast_strlen_zero(exten_name)) {
11363
11364
11365
11366
11367 res = 0;
11368 } else {
11369 res = ast_str_case_hash(exten_name);
11370 }
11371
11372 return res;
11373 }
11374
11375 static int hint_cmp(void *obj, void *arg, int flags)
11376 {
11377 const struct ast_hint *hint = obj;
11378 const struct ast_exten *exten = arg;
11379
11380 return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
11381 }
11382
11383 static int statecbs_cmp(void *obj, void *arg, int flags)
11384 {
11385 const struct ast_state_cb *state_cb = obj;
11386 ast_state_cb_type change_cb = arg;
11387
11388 return (state_cb->change_cb == change_cb) ? CMP_MATCH | CMP_STOP : 0;
11389 }
11390
11391 static void pbx_shutdown(void)
11392 {
11393 if (hints) {
11394 ao2_ref(hints, -1);
11395 hints = NULL;
11396 }
11397 if (statecbs) {
11398 ao2_ref(statecbs, -1);
11399 statecbs = NULL;
11400 }
11401 if (contexts_table) {
11402 ast_hashtab_destroy(contexts_table, NULL);
11403 }
11404 pbx_builtin_clear_globals();
11405 }
11406
11407 int ast_pbx_init(void)
11408 {
11409 hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
11410 statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
11411
11412 ast_register_atexit(pbx_shutdown);
11413
11414 return (hints && statecbs) ? 0 : -1;
11415 }