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