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