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