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