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