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