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