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