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