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