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