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