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