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