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