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