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: 415999 $")
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, "%d", (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 if (strstr(e->app, "${") && e->exten[0] == '_') {
05887
05888 hint_new->laststate = AST_DEVICE_INVALID;
05889 hint_new->last_presence_state = AST_PRESENCE_INVALID;
05890 } else {
05891 hint_new->laststate = ast_extension_state2(e, NULL);
05892 if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
05893 hint_new->last_presence_state = presence_state;
05894 hint_new->last_presence_subtype = subtype;
05895 hint_new->last_presence_message = message;
05896 message = subtype = NULL;
05897 }
05898 }
05899
05900
05901 ao2_lock(hints);
05902
05903
05904 hint_found = ao2_find(hints, e, 0);
05905 if (hint_found) {
05906 ao2_ref(hint_found, -1);
05907 ao2_unlock(hints);
05908 ao2_ref(hint_new, -1);
05909 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
05910 ast_get_extension_name(e), ast_get_extension_app(e));
05911 return -1;
05912 }
05913
05914
05915 ast_debug(2, "HINTS: Adding hint %s: %s\n",
05916 ast_get_extension_name(e), ast_get_extension_app(e));
05917 ao2_link(hints, hint_new);
05918 if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
05919 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
05920 ast_get_extension_name(e),
05921 ast_get_context_name(ast_get_extension_context(e)));
05922 }
05923
05924 ao2_unlock(hints);
05925 ao2_ref(hint_new, -1);
05926
05927 return 0;
05928 }
05929
05930
05931 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
05932 {
05933 struct ast_hint *hint;
05934
05935 if (!oe || !ne) {
05936 return -1;
05937 }
05938
05939 ao2_lock(hints);
05940
05941
05942
05943
05944
05945 hint = ao2_find(hints, oe, OBJ_UNLINK);
05946 if (!hint) {
05947 ao2_unlock(hints);
05948 return -1;
05949 }
05950
05951 remove_hintdevice(hint);
05952
05953
05954 ao2_lock(hint);
05955 hint->exten = ne;
05956 ao2_unlock(hint);
05957 ao2_link(hints, hint);
05958 if (add_hintdevice(hint, ast_get_extension_app(ne))) {
05959 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
05960 ast_get_extension_name(ne),
05961 ast_get_context_name(ast_get_extension_context(ne)));
05962 }
05963
05964 ao2_unlock(hints);
05965 ao2_ref(hint, -1);
05966
05967 return 0;
05968 }
05969
05970
05971
05972 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
05973 {
05974 struct ast_exten *e = ast_hint_extension(c, context, exten);
05975
05976 if (e) {
05977 if (hint)
05978 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
05979 if (name) {
05980 const char *tmp = ast_get_extension_app_data(e);
05981 if (tmp)
05982 ast_copy_string(name, tmp, namesize);
05983 }
05984 return -1;
05985 }
05986 return 0;
05987 }
05988
05989
05990 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)
05991 {
05992 struct ast_exten *e = ast_hint_extension(c, context, exten);
05993
05994 if (!e) {
05995 return 0;
05996 }
05997
05998 if (hint) {
05999 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
06000 }
06001 if (name) {
06002 const char *tmp = ast_get_extension_app_data(e);
06003 if (tmp) {
06004 ast_str_set(name, namesize, "%s", tmp);
06005 }
06006 }
06007 return -1;
06008 }
06009
06010 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
06011 {
06012 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
06013 }
06014
06015 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
06016 {
06017 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
06018 }
06019
06020 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
06021 {
06022 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
06023 }
06024
06025 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
06026 {
06027 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
06028 }
06029
06030 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
06031 {
06032 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
06033 }
06034
06035 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)
06036 {
06037 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
06038 }
06039
06040 void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
06041 {
06042 int autoloopflag;
06043 int found;
06044 int spawn_error;
06045
06046 ast_channel_lock(chan);
06047
06048 if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
06049 ast_cdr_end(ast_channel_cdr(chan));
06050 }
06051
06052
06053 if (context != ast_channel_context(chan)) {
06054 ast_channel_context_set(chan, context);
06055 }
06056 ast_channel_exten_set(chan, "h");
06057 ast_channel_priority_set(chan, 1);
06058
06059
06060
06061
06062
06063 ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
06064
06065
06066 autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
06067 ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
06068 ast_channel_unlock(chan);
06069
06070 for (;;) {
06071 spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
06072 ast_channel_exten(chan), ast_channel_priority(chan),
06073 S_COR(ast_channel_caller(chan)->id.number.valid,
06074 ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
06075
06076 ast_channel_lock(chan);
06077 if (spawn_error) {
06078
06079 break;
06080 }
06081 ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
06082 ast_channel_unlock(chan);
06083 }
06084 if (found && spawn_error) {
06085
06086 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
06087 ast_channel_context(chan), ast_channel_exten(chan),
06088 ast_channel_priority(chan), ast_channel_name(chan));
06089 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
06090 ast_channel_context(chan), ast_channel_exten(chan),
06091 ast_channel_priority(chan), ast_channel_name(chan));
06092 }
06093
06094
06095 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN);
06096
06097
06098 ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
06099 ast_channel_unlock(chan);
06100 }
06101
06102 int ast_pbx_hangup_handler_run(struct ast_channel *chan)
06103 {
06104 struct ast_hangup_handler_list *handlers;
06105 struct ast_hangup_handler *h_handler;
06106
06107 ast_channel_lock(chan);
06108 handlers = ast_channel_hangup_handlers(chan);
06109 if (AST_LIST_EMPTY(handlers)) {
06110 ast_channel_unlock(chan);
06111 return 0;
06112 }
06113
06114 if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
06115 ast_cdr_end(ast_channel_cdr(chan));
06116 }
06117
06118
06119
06120
06121
06122 ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
06123
06124 for (;;) {
06125 handlers = ast_channel_hangup_handlers(chan);
06126 h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
06127 if (!h_handler) {
06128 break;
06129 }
06130
06131
06132
06133
06134
06135
06136
06137
06138
06139
06140
06141 manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerRun",
06142 "Channel: %s\r\n"
06143 "Uniqueid: %s\r\n"
06144 "Handler: %s\r\n",
06145 ast_channel_name(chan),
06146 ast_channel_uniqueid(chan),
06147 h_handler->args);
06148 ast_channel_unlock(chan);
06149
06150 ast_app_exec_sub(NULL, chan, h_handler->args, 1);
06151 ast_free(h_handler);
06152
06153 ast_channel_lock(chan);
06154 }
06155 ast_channel_unlock(chan);
06156 return 1;
06157 }
06158
06159 void ast_pbx_hangup_handler_init(struct ast_channel *chan)
06160 {
06161 struct ast_hangup_handler_list *handlers;
06162
06163 handlers = ast_channel_hangup_handlers(chan);
06164 AST_LIST_HEAD_INIT_NOLOCK(handlers);
06165 }
06166
06167 void ast_pbx_hangup_handler_destroy(struct ast_channel *chan)
06168 {
06169 struct ast_hangup_handler_list *handlers;
06170 struct ast_hangup_handler *h_handler;
06171
06172 ast_channel_lock(chan);
06173
06174
06175 handlers = ast_channel_hangup_handlers(chan);
06176 while ((h_handler = AST_LIST_REMOVE_HEAD(handlers, node))) {
06177 ast_free(h_handler);
06178 }
06179
06180 ast_channel_unlock(chan);
06181 }
06182
06183 int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
06184 {
06185 struct ast_hangup_handler_list *handlers;
06186 struct ast_hangup_handler *h_handler;
06187
06188 ast_channel_lock(chan);
06189 handlers = ast_channel_hangup_handlers(chan);
06190 h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
06191 if (h_handler) {
06192
06193
06194
06195
06196
06197
06198
06199
06200
06201
06202
06203
06204
06205
06206
06207
06208
06209 manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPop",
06210 "Channel: %s\r\n"
06211 "Uniqueid: %s\r\n"
06212 "Handler: %s\r\n",
06213 ast_channel_name(chan),
06214 ast_channel_uniqueid(chan),
06215 h_handler->args);
06216 }
06217 ast_channel_unlock(chan);
06218 if (h_handler) {
06219 ast_free(h_handler);
06220 return 1;
06221 }
06222 return 0;
06223 }
06224
06225 void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
06226 {
06227 struct ast_hangup_handler_list *handlers;
06228 struct ast_hangup_handler *h_handler;
06229 const char *expanded_handler;
06230
06231 if (ast_strlen_zero(handler)) {
06232 return;
06233 }
06234
06235 expanded_handler = ast_app_expand_sub_args(chan, handler);
06236 if (!expanded_handler) {
06237 return;
06238 }
06239 h_handler = ast_malloc(sizeof(*h_handler) + 1 + strlen(expanded_handler));
06240 if (!h_handler) {
06241 ast_free((char *) expanded_handler);
06242 return;
06243 }
06244 strcpy(h_handler->args, expanded_handler);
06245 ast_free((char *) expanded_handler);
06246
06247 ast_channel_lock(chan);
06248
06249 handlers = ast_channel_hangup_handlers(chan);
06250 AST_LIST_INSERT_HEAD(handlers, h_handler, node);
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261
06262
06263
06264
06265
06266
06267
06268
06269 manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPush",
06270 "Channel: %s\r\n"
06271 "Uniqueid: %s\r\n"
06272 "Handler: %s\r\n",
06273 ast_channel_name(chan),
06274 ast_channel_uniqueid(chan),
06275 h_handler->args);
06276
06277 ast_channel_unlock(chan);
06278 }
06279
06280 #define HANDLER_FORMAT "%-30s %s\n"
06281
06282
06283
06284
06285
06286
06287
06288
06289
06290
06291 static void ast_pbx_hangup_handler_headers(int fd)
06292 {
06293 ast_cli(fd, HANDLER_FORMAT, "Channel", "Handler");
06294 }
06295
06296
06297
06298
06299
06300
06301
06302
06303
06304
06305
06306 static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
06307 {
06308 struct ast_hangup_handler_list *handlers;
06309 struct ast_hangup_handler *h_handler;
06310 int first = 1;
06311
06312 ast_channel_lock(chan);
06313 handlers = ast_channel_hangup_handlers(chan);
06314 AST_LIST_TRAVERSE(handlers, h_handler, node) {
06315 ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
06316 first = 0;
06317 }
06318 ast_channel_unlock(chan);
06319 }
06320
06321
06322
06323
06324 static char *handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06325 {
06326 struct ast_channel *chan;
06327
06328 switch (cmd) {
06329 case CLI_INIT:
06330 e->command = "core show hanguphandlers";
06331 e->usage =
06332 "Usage: core show hanguphandlers <channel>\n"
06333 " Show hangup handlers of a specified channel.\n";
06334 return NULL;
06335 case CLI_GENERATE:
06336 return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
06337 }
06338
06339 if (a->argc < 4) {
06340 return CLI_SHOWUSAGE;
06341 }
06342
06343 chan = ast_channel_get_by_name(a->argv[3]);
06344 if (!chan) {
06345 ast_cli(a->fd, "Channel does not exist.\n");
06346 return CLI_FAILURE;
06347 }
06348
06349 ast_pbx_hangup_handler_headers(a->fd);
06350 ast_pbx_hangup_handler_show(a->fd, chan);
06351
06352 ast_channel_unref(chan);
06353
06354 return CLI_SUCCESS;
06355 }
06356
06357
06358
06359
06360 static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06361 {
06362 struct ast_channel_iterator *iter;
06363 struct ast_channel *chan;
06364
06365 switch (cmd) {
06366 case CLI_INIT:
06367 e->command = "core show hanguphandlers all";
06368 e->usage =
06369 "Usage: core show hanguphandlers all\n"
06370 " Show hangup handlers for all channels.\n";
06371 return NULL;
06372 case CLI_GENERATE:
06373 return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
06374 }
06375
06376 if (a->argc < 4) {
06377 return CLI_SHOWUSAGE;
06378 }
06379
06380 iter = ast_channel_iterator_all_new();
06381 if (!iter) {
06382 return CLI_FAILURE;
06383 }
06384
06385 ast_pbx_hangup_handler_headers(a->fd);
06386 for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
06387 ast_pbx_hangup_handler_show(a->fd, chan);
06388 }
06389 ast_channel_iterator_destroy(iter);
06390
06391 return CLI_SUCCESS;
06392 }
06393
06394
06395 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
06396 {
06397 ast_channel_lock(c);
06398 ast_channel_exten_set(c, exten);
06399 ast_channel_priority_set(c, pri);
06400 ast_channel_unlock(c);
06401 }
06402
06403
06404
06405
06406
06407
06408
06409
06410 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
06411 {
06412 int digit;
06413
06414 buf[pos] = '\0';
06415 while (ast_matchmore_extension(c, ast_channel_context(c), buf, 1,
06416 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06417
06418
06419 digit = ast_waitfordigit(c, waittime);
06420 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
06421 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
06422 } else {
06423 if (!digit)
06424 break;
06425 if (digit < 0)
06426 return -1;
06427 if (pos < buflen - 1) {
06428 buf[pos++] = digit;
06429 buf[pos] = '\0';
06430 }
06431 waittime = ast_channel_pbx(c)->dtimeoutms;
06432 }
06433 }
06434 return 0;
06435 }
06436
06437 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
06438 struct ast_pbx_args *args)
06439 {
06440 int found = 0;
06441 int res = 0;
06442 int autoloopflag;
06443 int error = 0;
06444 struct ast_pbx *pbx;
06445 struct ast_callid *callid;
06446
06447
06448 if (ast_channel_pbx(c)) {
06449 ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
06450
06451 ast_free(ast_channel_pbx(c));
06452 }
06453 if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
06454 return -1;
06455 }
06456
06457 callid = ast_read_threadstorage_callid();
06458
06459 if (!callid) {
06460
06461
06462
06463 callid = ast_channel_callid(c);
06464 if (!callid) {
06465 callid = ast_create_callid();
06466 if (callid) {
06467 ast_channel_callid_set(c, callid);
06468 }
06469 }
06470 ast_callid_threadassoc_add(callid);
06471 callid = ast_callid_unref(callid);
06472 } else {
06473
06474 ast_callid_unref(callid);
06475 }
06476
06477 ast_channel_pbx_set(c, pbx);
06478
06479 ast_channel_pbx(c)->rtimeoutms = 10000;
06480 ast_channel_pbx(c)->dtimeoutms = 5000;
06481
06482 autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
06483 ast_set_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
06484
06485 if (ast_strlen_zero(ast_channel_exten(c))) {
06486
06487 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));
06488
06489
06490
06491
06492 set_ext_pri(c, "s", 1);
06493 }
06494
06495 ast_channel_lock(c);
06496 if (ast_channel_cdr(c)) {
06497
06498 ast_cdr_update(c);
06499 }
06500 ast_channel_unlock(c);
06501 for (;;) {
06502 char dst_exten[256];
06503 int pos = 0;
06504 int digit = 0;
06505 int invalid = 0;
06506 int timeout = 0;
06507
06508
06509 dst_exten[pos] = '\0';
06510
06511
06512 while (!(res = ast_spawn_extension(c, ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
06513 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL),
06514 &found, 1))) {
06515 if (!ast_check_hangup(c)) {
06516 ast_channel_priority_set(c, ast_channel_priority(c) + 1);
06517 continue;
06518 }
06519
06520
06521 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
06522 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
06523 continue;
06524 }
06525 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
06526 if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
06527 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06528 set_ext_pri(c, "T", 1);
06529
06530 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06531 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06532 continue;
06533 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06534 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06535 raise_exception(c, "ABSOLUTETIMEOUT", 1);
06536
06537 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06538 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06539 continue;
06540 }
06541
06542
06543 error = 1;
06544 break;
06545 }
06546 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
06547 ast_channel_exten(c), ast_channel_priority(c));
06548 error = 1;
06549 break;
06550 }
06551 if (found && res) {
06552
06553 if (strchr("0123456789ABCDEF*#", res)) {
06554 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
06555 pos = 0;
06556 dst_exten[pos++] = digit = res;
06557 dst_exten[pos] = '\0';
06558 } else if (res == AST_PBX_INCOMPLETE) {
06559 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));
06560 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));
06561
06562
06563 if (!ast_matchmore_extension(c, ast_channel_context(c), ast_channel_exten(c), 1,
06564 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06565 invalid = 1;
06566 } else {
06567 ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
06568 digit = 1;
06569 pos = strlen(dst_exten);
06570 }
06571 } else {
06572 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));
06573 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));
06574
06575 if ((res == AST_PBX_ERROR)
06576 && ast_exists_extension(c, ast_channel_context(c), "e", 1,
06577 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06578
06579 if (!strcmp(ast_channel_exten(c), "e")) {
06580 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));
06581 error = 1;
06582 } else {
06583 raise_exception(c, "ERROR", 1);
06584 continue;
06585 }
06586 }
06587
06588 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
06589 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
06590 continue;
06591 }
06592 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
06593 if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
06594 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06595 set_ext_pri(c, "T", 1);
06596
06597 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06598 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06599 continue;
06600 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06601 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06602 raise_exception(c, "ABSOLUTETIMEOUT", 1);
06603
06604 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06605 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06606 continue;
06607 }
06608
06609 }
06610 ast_channel_lock(c);
06611 if (ast_channel_cdr(c)) {
06612 ast_cdr_update(c);
06613 }
06614 ast_channel_unlock(c);
06615 error = 1;
06616 break;
06617 }
06618 }
06619 if (error)
06620 break;
06621
06622
06623
06624
06625
06626
06627 if (invalid
06628 || (ast_strlen_zero(dst_exten) &&
06629 !ast_exists_extension(c, ast_channel_context(c), ast_channel_exten(c), 1,
06630 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
06631
06632
06633
06634
06635
06636 if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
06637 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06638 ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
06639 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
06640 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
06641 set_ext_pri(c, "i", 1);
06642 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06643 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06644 raise_exception(c, "INVALID", 1);
06645 } else {
06646 ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
06647 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
06648 error = 1;
06649 break;
06650 }
06651 } else if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
06652
06653 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06654 } else {
06655 int waittime = 0;
06656 if (digit)
06657 waittime = ast_channel_pbx(c)->dtimeoutms;
06658 else if (!autofallthrough)
06659 waittime = ast_channel_pbx(c)->rtimeoutms;
06660 if (!waittime) {
06661 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
06662 if (!status)
06663 status = "UNKNOWN";
06664 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
06665 if (!strcasecmp(status, "CONGESTION"))
06666 res = pbx_builtin_congestion(c, "10");
06667 else if (!strcasecmp(status, "CHANUNAVAIL"))
06668 res = pbx_builtin_congestion(c, "10");
06669 else if (!strcasecmp(status, "BUSY"))
06670 res = pbx_builtin_busy(c, "10");
06671 error = 1;
06672 break;
06673 }
06674
06675 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
06676 break;
06677 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
06678 timeout = 1;
06679 if (!timeout
06680 && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
06681 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06682 set_ext_pri(c, dst_exten, 1);
06683 } else {
06684
06685 if (!timeout && !ast_strlen_zero(dst_exten)) {
06686
06687 if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
06688 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06689 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
06690 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
06691 set_ext_pri(c, "i", 1);
06692 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06693 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06694 raise_exception(c, "INVALID", 1);
06695 } else {
06696 ast_log(LOG_WARNING,
06697 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
06698 dst_exten, ast_channel_context(c));
06699 found = 1;
06700 break;
06701 }
06702 } else {
06703
06704 if (ast_exists_extension(c, ast_channel_context(c), "t", 1,
06705 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06706 ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
06707 set_ext_pri(c, "t", 1);
06708 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06709 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06710 raise_exception(c, "RESPONSETIMEOUT", 1);
06711 } else {
06712 ast_log(LOG_WARNING,
06713 "Timeout, but no rule 't' or 'e' in context '%s'\n",
06714 ast_channel_context(c));
06715 found = 1;
06716 break;
06717 }
06718 }
06719 }
06720 ast_channel_lock(c);
06721 if (ast_channel_cdr(c)) {
06722 ast_verb(2, "CDR updated on %s\n",ast_channel_name(c));
06723 ast_cdr_update(c);
06724 }
06725 ast_channel_unlock(c);
06726 }
06727 }
06728
06729 if (!found && !error) {
06730 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
06731 }
06732
06733 if (!args || !args->no_hangup_chan) {
06734 ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
06735 if (!ast_test_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN)
06736 && ast_exists_extension(c, ast_channel_context(c), "h", 1,
06737 S_COR(ast_channel_caller(c)->id.number.valid,
06738 ast_channel_caller(c)->id.number.str, NULL))) {
06739 ast_pbx_h_exten_run(c, ast_channel_context(c));
06740 }
06741 ast_pbx_hangup_handler_run(c);
06742 }
06743
06744 ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP);
06745 ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN);
06746 pbx_destroy(ast_channel_pbx(c));
06747 ast_channel_pbx_set(c, NULL);
06748
06749 if (!args || !args->no_hangup_chan) {
06750 ast_hangup(c);
06751 }
06752
06753 return 0;
06754 }
06755
06756
06757
06758
06759
06760
06761 static int increase_call_count(const struct ast_channel *c)
06762 {
06763 int failed = 0;
06764 double curloadavg;
06765 #if defined(HAVE_SYSINFO)
06766 long curfreemem;
06767 struct sysinfo sys_info;
06768 #endif
06769
06770 ast_mutex_lock(&maxcalllock);
06771 if (option_maxcalls) {
06772 if (countcalls >= option_maxcalls) {
06773 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, ast_channel_name(c));
06774 failed = -1;
06775 }
06776 }
06777 if (option_maxload) {
06778 getloadavg(&curloadavg, 1);
06779 if (curloadavg >= option_maxload) {
06780 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, ast_channel_name(c), curloadavg);
06781 failed = -1;
06782 }
06783 }
06784 #if defined(HAVE_SYSINFO)
06785 if (option_minmemfree) {
06786 if (!sysinfo(&sys_info)) {
06787
06788
06789 curfreemem = sys_info.freeram * sys_info.mem_unit;
06790 curfreemem /= 1024 * 1024;
06791 if (curfreemem < option_minmemfree) {
06792 ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
06793 failed = -1;
06794 }
06795 }
06796 }
06797 #endif
06798
06799 if (!failed) {
06800 countcalls++;
06801 totalcalls++;
06802 }
06803 ast_mutex_unlock(&maxcalllock);
06804
06805 return failed;
06806 }
06807
06808 static void decrease_call_count(void)
06809 {
06810 ast_mutex_lock(&maxcalllock);
06811 if (countcalls > 0)
06812 countcalls--;
06813 ast_mutex_unlock(&maxcalllock);
06814 }
06815
06816 static void destroy_exten(struct ast_exten *e)
06817 {
06818 if (e->priority == PRIORITY_HINT)
06819 ast_remove_hint(e);
06820
06821 if (e->peer_table)
06822 ast_hashtab_destroy(e->peer_table,0);
06823 if (e->peer_label_table)
06824 ast_hashtab_destroy(e->peer_label_table, 0);
06825 if (e->datad)
06826 e->datad(e->data);
06827 ast_free(e);
06828 }
06829
06830 static void *pbx_thread(void *data)
06831 {
06832
06833
06834
06835
06836
06837
06838
06839
06840 struct ast_channel *c = data;
06841
06842 __ast_pbx_run(c, NULL);
06843 decrease_call_count();
06844
06845 pthread_exit(NULL);
06846
06847 return NULL;
06848 }
06849
06850 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
06851 {
06852 pthread_t t;
06853
06854 if (!c) {
06855 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
06856 return AST_PBX_FAILED;
06857 }
06858
06859 if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
06860 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
06861 return AST_PBX_FAILED;
06862 }
06863
06864 if (increase_call_count(c))
06865 return AST_PBX_CALL_LIMIT;
06866
06867
06868 if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
06869 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
06870 decrease_call_count();
06871 return AST_PBX_FAILED;
06872 }
06873
06874 return AST_PBX_SUCCESS;
06875 }
06876
06877 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
06878 {
06879 enum ast_pbx_result res = AST_PBX_SUCCESS;
06880
06881 if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
06882 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
06883 return AST_PBX_FAILED;
06884 }
06885
06886 if (increase_call_count(c)) {
06887 return AST_PBX_CALL_LIMIT;
06888 }
06889
06890 res = __ast_pbx_run(c, args);
06891
06892 decrease_call_count();
06893
06894 return res;
06895 }
06896
06897 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
06898 {
06899 return ast_pbx_run_args(c, NULL);
06900 }
06901
06902 int ast_active_calls(void)
06903 {
06904 return countcalls;
06905 }
06906
06907 int ast_processed_calls(void)
06908 {
06909 return totalcalls;
06910 }
06911
06912 int pbx_set_autofallthrough(int newval)
06913 {
06914 int oldval = autofallthrough;
06915 autofallthrough = newval;
06916 return oldval;
06917 }
06918
06919 int pbx_set_extenpatternmatchnew(int newval)
06920 {
06921 int oldval = extenpatternmatchnew;
06922 extenpatternmatchnew = newval;
06923 return oldval;
06924 }
06925
06926 void pbx_set_overrideswitch(const char *newval)
06927 {
06928 if (overrideswitch) {
06929 ast_free(overrideswitch);
06930 }
06931 if (!ast_strlen_zero(newval)) {
06932 overrideswitch = ast_strdup(newval);
06933 } else {
06934 overrideswitch = NULL;
06935 }
06936 }
06937
06938
06939
06940
06941
06942 static struct ast_context *find_context(const char *context)
06943 {
06944 struct fake_context item;
06945
06946 ast_copy_string(item.name, context, sizeof(item.name));
06947
06948 return ast_hashtab_lookup(contexts_table, &item);
06949 }
06950
06951
06952
06953
06954
06955
06956 static struct ast_context *find_context_locked(const char *context)
06957 {
06958 struct ast_context *c;
06959 struct fake_context item;
06960
06961 ast_copy_string(item.name, context, sizeof(item.name));
06962
06963 ast_rdlock_contexts();
06964 c = ast_hashtab_lookup(contexts_table, &item);
06965 if (!c) {
06966 ast_unlock_contexts();
06967 }
06968
06969 return c;
06970 }
06971
06972
06973
06974
06975
06976
06977
06978 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
06979 {
06980 int ret = -1;
06981 struct ast_context *c;
06982
06983 c = find_context_locked(context);
06984 if (c) {
06985
06986 ret = ast_context_remove_include2(c, include, registrar);
06987 ast_unlock_contexts();
06988 }
06989 return ret;
06990 }
06991
06992
06993
06994
06995
06996
06997
06998
06999
07000
07001 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
07002 {
07003 struct ast_include *i, *pi = NULL;
07004 int ret = -1;
07005
07006 ast_wrlock_context(con);
07007
07008
07009 for (i = con->includes; i; pi = i, i = i->next) {
07010 if (!strcmp(i->name, include) &&
07011 (!registrar || !strcmp(i->registrar, registrar))) {
07012
07013 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
07014 if (pi)
07015 pi->next = i->next;
07016 else
07017 con->includes = i->next;
07018
07019 ast_destroy_timing(&(i->timing));
07020 ast_free(i);
07021 ret = 0;
07022 break;
07023 }
07024 }
07025
07026 ast_unlock_context(con);
07027
07028 return ret;
07029 }
07030
07031
07032
07033
07034
07035
07036 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
07037 {
07038 int ret = -1;
07039 struct ast_context *c;
07040
07041 c = find_context_locked(context);
07042 if (c) {
07043
07044 ret = ast_context_remove_switch2(c, sw, data, registrar);
07045 ast_unlock_contexts();
07046 }
07047 return ret;
07048 }
07049
07050
07051
07052
07053
07054
07055
07056
07057
07058 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
07059 {
07060 struct ast_sw *i;
07061 int ret = -1;
07062
07063 ast_wrlock_context(con);
07064
07065
07066 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
07067 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
07068 (!registrar || !strcmp(i->registrar, registrar))) {
07069
07070 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
07071 AST_LIST_REMOVE_CURRENT(list);
07072 ast_free(i);
07073 ret = 0;
07074 break;
07075 }
07076 }
07077 AST_LIST_TRAVERSE_SAFE_END;
07078
07079 ast_unlock_context(con);
07080
07081 return ret;
07082 }
07083
07084
07085 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
07086 {
07087 return ast_context_remove_extension_callerid(context, extension, priority, NULL, AST_EXT_MATCHCID_ANY, registrar);
07088 }
07089
07090 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
07091 {
07092 int ret = -1;
07093 struct ast_context *c;
07094
07095 c = find_context_locked(context);
07096 if (c) {
07097 ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid,
07098 matchcallerid, registrar, 0);
07099 ast_unlock_contexts();
07100 }
07101
07102 return ret;
07103 }
07104
07105
07106
07107
07108
07109
07110
07111
07112
07113
07114
07115 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
07116 {
07117 return ast_context_remove_extension_callerid2(con, extension, priority, NULL, AST_EXT_MATCHCID_ANY, registrar, already_locked);
07118 }
07119
07120 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)
07121 {
07122 struct ast_exten *exten, *prev_exten = NULL;
07123 struct ast_exten *peer;
07124 struct ast_exten ex, *exten2, *exten3;
07125 char dummy_name[1024];
07126 struct ast_exten *previous_peer = NULL;
07127 struct ast_exten *next_peer = NULL;
07128 int found = 0;
07129
07130 if (!already_locked)
07131 ast_wrlock_context(con);
07132
07133 #ifdef NEED_DEBUG
07134 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
07135 #endif
07136 #ifdef CONTEXT_DEBUG
07137 check_contexts(__FILE__, __LINE__);
07138 #endif
07139
07140 ex.exten = dummy_name;
07141 ex.matchcid = matchcallerid;
07142 ex.cidmatch = callerid;
07143 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
07144 exten = ast_hashtab_lookup(con->root_table, &ex);
07145 if (exten) {
07146 if (priority == 0) {
07147 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
07148 if (!exten2)
07149 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);
07150 if (con->pattern_tree) {
07151 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
07152
07153 if (x->exten) {
07154 x->deleted = 1;
07155 x->exten = 0;
07156 } else {
07157 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
07158 }
07159 }
07160 } else {
07161 ex.priority = priority;
07162 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
07163 if (exten2) {
07164 if (exten2->label) {
07165 exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
07166 if (!exten3)
07167 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);
07168 }
07169
07170 exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
07171 if (!exten3)
07172 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);
07173 if (exten2 == exten && exten2->peer) {
07174 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
07175 ast_hashtab_insert_immediate(con->root_table, exten2->peer);
07176 }
07177 if (ast_hashtab_size(exten->peer_table) == 0) {
07178
07179
07180 exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
07181 if (!exten3)
07182 ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
07183 if (con->pattern_tree) {
07184 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
07185 if (x->exten) {
07186 x->deleted = 1;
07187 x->exten = 0;
07188 }
07189 }
07190 }
07191 } else {
07192 ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
07193 priority, exten->exten, con->name);
07194 }
07195 }
07196 } else {
07197
07198 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
07199 extension, con->name);
07200 }
07201 #ifdef NEED_DEBUG
07202 if (con->pattern_tree) {
07203 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
07204 log_match_char_tree(con->pattern_tree, " ");
07205 }
07206 #endif
07207
07208
07209 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
07210 if (!strcmp(exten->exten, extension) &&
07211 (!registrar || !strcmp(exten->registrar, registrar)) &&
07212 (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
07213 break;
07214 }
07215 if (!exten) {
07216
07217 if (!already_locked)
07218 ast_unlock_context(con);
07219 return -1;
07220 }
07221
07222
07223 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
07224 peer && !strcmp(peer->exten, extension) &&
07225 (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, callerid))) ;
07226 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
07227
07228 if ((priority == 0 || peer->priority == priority) &&
07229 (!registrar || !strcmp(peer->registrar, registrar) )) {
07230 found = 1;
07231
07232
07233 if (!previous_peer) {
07234
07235
07236
07237
07238 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
07239 if (peer->peer) {
07240
07241
07242 peer->peer->peer_table = peer->peer_table;
07243 peer->peer->peer_label_table = peer->peer_label_table;
07244 peer->peer_table = NULL;
07245 peer->peer_label_table = NULL;
07246 }
07247 if (!prev_exten) {
07248 con->root = next_node;
07249 } else {
07250 prev_exten->next = next_node;
07251 }
07252 if (peer->peer) {
07253 peer->peer->next = peer->next;
07254 }
07255 } else {
07256 previous_peer->peer = peer->peer;
07257 }
07258
07259
07260
07261 destroy_exten(peer);
07262 } else {
07263 previous_peer = peer;
07264 }
07265 }
07266 if (!already_locked)
07267 ast_unlock_context(con);
07268 return found ? 0 : -1;
07269 }
07270
07271
07272
07273
07274
07275
07276
07277 int ast_context_lockmacro(const char *context)
07278 {
07279 struct ast_context *c;
07280 int ret = -1;
07281
07282 c = find_context_locked(context);
07283 if (c) {
07284 ast_unlock_contexts();
07285
07286
07287 ret = ast_mutex_lock(&c->macrolock);
07288 }
07289
07290 return ret;
07291 }
07292
07293
07294
07295
07296
07297
07298 int ast_context_unlockmacro(const char *context)
07299 {
07300 struct ast_context *c;
07301 int ret = -1;
07302
07303 c = find_context_locked(context);
07304 if (c) {
07305 ast_unlock_contexts();
07306
07307
07308 ret = ast_mutex_unlock(&c->macrolock);
07309 }
07310
07311 return ret;
07312 }
07313
07314
07315 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
07316 {
07317 struct ast_app *tmp, *cur = NULL;
07318 char tmps[80];
07319 int length, res;
07320 #ifdef AST_XML_DOCS
07321 char *tmpxml;
07322 #endif
07323
07324 AST_RWLIST_WRLOCK(&apps);
07325 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
07326 if (!(res = strcasecmp(app, tmp->name))) {
07327 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
07328 AST_RWLIST_UNLOCK(&apps);
07329 return -1;
07330 } else if (res < 0)
07331 break;
07332 }
07333
07334 length = sizeof(*tmp) + strlen(app) + 1;
07335
07336 if (!(tmp = ast_calloc(1, length))) {
07337 AST_RWLIST_UNLOCK(&apps);
07338 return -1;
07339 }
07340
07341 if (ast_string_field_init(tmp, 128)) {
07342 AST_RWLIST_UNLOCK(&apps);
07343 ast_free(tmp);
07344 return -1;
07345 }
07346
07347 strcpy(tmp->name, app);
07348 tmp->execute = execute;
07349 tmp->module = mod;
07350
07351 #ifdef AST_XML_DOCS
07352
07353 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
07354
07355 tmpxml = ast_xmldoc_build_synopsis("application", app, ast_module_name(tmp->module));
07356 ast_string_field_set(tmp, synopsis, tmpxml);
07357 ast_free(tmpxml);
07358
07359
07360 tmpxml = ast_xmldoc_build_description("application", app, ast_module_name(tmp->module));
07361 ast_string_field_set(tmp, description, tmpxml);
07362 ast_free(tmpxml);
07363
07364
07365 tmpxml = ast_xmldoc_build_syntax("application", app, ast_module_name(tmp->module));
07366 ast_string_field_set(tmp, syntax, tmpxml);
07367 ast_free(tmpxml);
07368
07369
07370 tmpxml = ast_xmldoc_build_arguments("application", app, ast_module_name(tmp->module));
07371 ast_string_field_set(tmp, arguments, tmpxml);
07372 ast_free(tmpxml);
07373
07374
07375 tmpxml = ast_xmldoc_build_seealso("application", app, ast_module_name(tmp->module));
07376 ast_string_field_set(tmp, seealso, tmpxml);
07377 ast_free(tmpxml);
07378 tmp->docsrc = AST_XML_DOC;
07379 } else {
07380 #endif
07381 ast_string_field_set(tmp, synopsis, synopsis);
07382 ast_string_field_set(tmp, description, description);
07383 #ifdef AST_XML_DOCS
07384 tmp->docsrc = AST_STATIC_DOC;
07385 }
07386 #endif
07387
07388
07389 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
07390 if (strcasecmp(tmp->name, cur->name) < 0) {
07391 AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
07392 break;
07393 }
07394 }
07395 AST_RWLIST_TRAVERSE_SAFE_END;
07396 if (!cur)
07397 AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
07398
07399 ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
07400
07401 AST_RWLIST_UNLOCK(&apps);
07402
07403 return 0;
07404 }
07405
07406
07407
07408
07409
07410 int ast_register_switch(struct ast_switch *sw)
07411 {
07412 struct ast_switch *tmp;
07413
07414 AST_RWLIST_WRLOCK(&switches);
07415 AST_RWLIST_TRAVERSE(&switches, tmp, list) {
07416 if (!strcasecmp(tmp->name, sw->name)) {
07417 AST_RWLIST_UNLOCK(&switches);
07418 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
07419 return -1;
07420 }
07421 }
07422 AST_RWLIST_INSERT_TAIL(&switches, sw, list);
07423 AST_RWLIST_UNLOCK(&switches);
07424
07425 return 0;
07426 }
07427
07428 void ast_unregister_switch(struct ast_switch *sw)
07429 {
07430 AST_RWLIST_WRLOCK(&switches);
07431 AST_RWLIST_REMOVE(&switches, sw, list);
07432 AST_RWLIST_UNLOCK(&switches);
07433 }
07434
07435
07436
07437
07438
07439 static void print_app_docs(struct ast_app *aa, int fd)
07440 {
07441
07442 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40];
07443 char seealsotitle[40];
07444 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL;
07445 char *seealso = NULL;
07446 int syntax_size, synopsis_size, description_size, arguments_size, seealso_size;
07447
07448 snprintf(info, sizeof(info), "\n -= Info about application '%s' =- \n\n", aa->name);
07449 term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
07450
07451 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
07452 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
07453 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
07454 term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
07455 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
07456
07457 #ifdef AST_XML_DOCS
07458 if (aa->docsrc == AST_XML_DOC) {
07459 description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
07460 arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
07461 synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
07462 seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
07463
07464 if (!synopsis || !description || !arguments || !seealso) {
07465 goto return_cleanup;
07466 }
07467 } else
07468 #endif
07469 {
07470 synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07471 synopsis = ast_malloc(synopsis_size);
07472
07473 description_size = strlen(S_OR(aa->description, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07474 description = ast_malloc(description_size);
07475
07476 arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07477 arguments = ast_malloc(arguments_size);
07478
07479 seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07480 seealso = ast_malloc(seealso_size);
07481
07482 if (!synopsis || !description || !arguments || !seealso) {
07483 goto return_cleanup;
07484 }
07485
07486 term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
07487 term_color(description, S_OR(aa->description, "Not available"), COLOR_CYAN, 0, description_size);
07488 term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
07489 term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
07490 }
07491
07492
07493 syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07494 if (!(syntax = ast_malloc(syntax_size))) {
07495 goto return_cleanup;
07496 }
07497 term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
07498
07499 ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
07500 infotitle, syntitle, synopsis, destitle, description,
07501 stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
07502
07503 return_cleanup:
07504 ast_free(description);
07505 ast_free(arguments);
07506 ast_free(synopsis);
07507 ast_free(seealso);
07508 ast_free(syntax);
07509 }
07510
07511
07512
07513
07514 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07515 {
07516 struct ast_app *aa;
07517 int app, no_registered_app = 1;
07518
07519 switch (cmd) {
07520 case CLI_INIT:
07521 e->command = "core show application";
07522 e->usage =
07523 "Usage: core show application <application> [<application> [<application> [...]]]\n"
07524 " Describes a particular application.\n";
07525 return NULL;
07526 case CLI_GENERATE:
07527
07528
07529
07530
07531
07532 return ast_complete_applications(a->line, a->word, a->n);
07533 }
07534
07535 if (a->argc < 4) {
07536 return CLI_SHOWUSAGE;
07537 }
07538
07539 AST_RWLIST_RDLOCK(&apps);
07540 AST_RWLIST_TRAVERSE(&apps, aa, list) {
07541
07542 for (app = 3; app < a->argc; app++) {
07543 if (strcasecmp(aa->name, a->argv[app])) {
07544 continue;
07545 }
07546
07547
07548 no_registered_app = 0;
07549
07550 print_app_docs(aa, a->fd);
07551 }
07552 }
07553 AST_RWLIST_UNLOCK(&apps);
07554
07555
07556 if (no_registered_app) {
07557 ast_cli(a->fd, "Your application(s) is (are) not registered\n");
07558 return CLI_FAILURE;
07559 }
07560
07561 return CLI_SUCCESS;
07562 }
07563
07564
07565 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07566 {
07567 struct ast_hint *hint;
07568 int num = 0;
07569 int watchers;
07570 struct ao2_iterator i;
07571
07572 switch (cmd) {
07573 case CLI_INIT:
07574 e->command = "core show hints";
07575 e->usage =
07576 "Usage: core show hints\n"
07577 " List registered hints.\n"
07578 " Hint details are shown in four columns. In order from left to right, they are:\n"
07579 " 1. Hint extension URI.\n"
07580 " 2. Mapped device state identifiers.\n"
07581 " 3. Current extension state. The aggregate of mapped device states.\n"
07582 " 4. Watchers - number of subscriptions and other entities watching this hint.\n";
07583 return NULL;
07584 case CLI_GENERATE:
07585 return NULL;
07586 }
07587
07588 if (ao2_container_count(hints) == 0) {
07589 ast_cli(a->fd, "There are no registered dialplan hints\n");
07590 return CLI_SUCCESS;
07591 }
07592
07593 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
07594
07595 i = ao2_iterator_init(hints, 0);
07596 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07597 ao2_lock(hint);
07598 if (!hint->exten) {
07599
07600 ao2_unlock(hint);
07601 continue;
07602 }
07603 watchers = ao2_container_count(hint->callbacks);
07604 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
07605 ast_get_extension_name(hint->exten),
07606 ast_get_context_name(ast_get_extension_context(hint->exten)),
07607 ast_get_extension_app(hint->exten),
07608 ast_extension_state2str(hint->laststate), watchers);
07609 ao2_unlock(hint);
07610 num++;
07611 }
07612 ao2_iterator_destroy(&i);
07613
07614 ast_cli(a->fd, "----------------\n");
07615 ast_cli(a->fd, "- %d hints registered\n", num);
07616 return CLI_SUCCESS;
07617 }
07618
07619
07620 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
07621 {
07622 struct ast_hint *hint;
07623 char *ret = NULL;
07624 int which = 0;
07625 int wordlen;
07626 struct ao2_iterator i;
07627
07628 if (pos != 3)
07629 return NULL;
07630
07631 wordlen = strlen(word);
07632
07633
07634 i = ao2_iterator_init(hints, 0);
07635 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07636 ao2_lock(hint);
07637 if (!hint->exten) {
07638
07639 ao2_unlock(hint);
07640 continue;
07641 }
07642 if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
07643 ret = ast_strdup(ast_get_extension_name(hint->exten));
07644 ao2_unlock(hint);
07645 ao2_ref(hint, -1);
07646 break;
07647 }
07648 ao2_unlock(hint);
07649 }
07650 ao2_iterator_destroy(&i);
07651
07652 return ret;
07653 }
07654
07655
07656 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07657 {
07658 struct ast_hint *hint;
07659 int watchers;
07660 int num = 0, extenlen;
07661 struct ao2_iterator i;
07662
07663 switch (cmd) {
07664 case CLI_INIT:
07665 e->command = "core show hint";
07666 e->usage =
07667 "Usage: core show hint <exten>\n"
07668 " List registered hint.\n"
07669 " Hint details are shown in four columns. In order from left to right, they are:\n"
07670 " 1. Hint extension URI.\n"
07671 " 2. Mapped device state identifiers.\n"
07672 " 3. Current extension state. The aggregate of mapped device states.\n"
07673 " 4. Watchers - number of subscriptions and other entities watching this hint.\n";
07674
07675 return NULL;
07676 case CLI_GENERATE:
07677 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
07678 }
07679
07680 if (a->argc < 4)
07681 return CLI_SHOWUSAGE;
07682
07683 if (ao2_container_count(hints) == 0) {
07684 ast_cli(a->fd, "There are no registered dialplan hints\n");
07685 return CLI_SUCCESS;
07686 }
07687
07688 extenlen = strlen(a->argv[3]);
07689 i = ao2_iterator_init(hints, 0);
07690 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07691 ao2_lock(hint);
07692 if (!hint->exten) {
07693
07694 ao2_unlock(hint);
07695 continue;
07696 }
07697 if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
07698 watchers = ao2_container_count(hint->callbacks);
07699 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
07700 ast_get_extension_name(hint->exten),
07701 ast_get_context_name(ast_get_extension_context(hint->exten)),
07702 ast_get_extension_app(hint->exten),
07703 ast_extension_state2str(hint->laststate), watchers);
07704 num++;
07705 }
07706 ao2_unlock(hint);
07707 }
07708 ao2_iterator_destroy(&i);
07709 if (!num)
07710 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
07711 else
07712 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
07713 return CLI_SUCCESS;
07714 }
07715
07716
07717
07718 static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07719 {
07720 struct ast_switch *sw;
07721
07722 switch (cmd) {
07723 case CLI_INIT:
07724 e->command = "core show switches";
07725 e->usage =
07726 "Usage: core show switches\n"
07727 " List registered switches\n";
07728 return NULL;
07729 case CLI_GENERATE:
07730 return NULL;
07731 }
07732
07733 AST_RWLIST_RDLOCK(&switches);
07734
07735 if (AST_RWLIST_EMPTY(&switches)) {
07736 AST_RWLIST_UNLOCK(&switches);
07737 ast_cli(a->fd, "There are no registered alternative switches\n");
07738 return CLI_SUCCESS;
07739 }
07740
07741 ast_cli(a->fd, "\n -= Registered Asterisk Alternative Switches =-\n");
07742 AST_RWLIST_TRAVERSE(&switches, sw, list)
07743 ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
07744
07745 AST_RWLIST_UNLOCK(&switches);
07746
07747 return CLI_SUCCESS;
07748 }
07749
07750 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07751 {
07752 struct ast_app *aa;
07753 int like = 0, describing = 0;
07754 int total_match = 0;
07755 int total_apps = 0;
07756 static const char * const choices[] = { "like", "describing", NULL };
07757
07758 switch (cmd) {
07759 case CLI_INIT:
07760 e->command = "core show applications [like|describing]";
07761 e->usage =
07762 "Usage: core show applications [{like|describing} <text>]\n"
07763 " List applications which are currently available.\n"
07764 " If 'like', <text> will be a substring of the app name\n"
07765 " If 'describing', <text> will be a substring of the description\n";
07766 return NULL;
07767 case CLI_GENERATE:
07768 return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
07769 }
07770
07771 AST_RWLIST_RDLOCK(&apps);
07772
07773 if (AST_RWLIST_EMPTY(&apps)) {
07774 ast_cli(a->fd, "There are no registered applications\n");
07775 AST_RWLIST_UNLOCK(&apps);
07776 return CLI_SUCCESS;
07777 }
07778
07779
07780 if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
07781 like = 1;
07782 } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
07783 describing = 1;
07784 }
07785
07786
07787 if ((!like) && (!describing)) {
07788 ast_cli(a->fd, " -= Registered Asterisk Applications =-\n");
07789 } else {
07790 ast_cli(a->fd, " -= Matching Asterisk Applications =-\n");
07791 }
07792
07793 AST_RWLIST_TRAVERSE(&apps, aa, list) {
07794 int printapp = 0;
07795 total_apps++;
07796 if (like) {
07797 if (strcasestr(aa->name, a->argv[4])) {
07798 printapp = 1;
07799 total_match++;
07800 }
07801 } else if (describing) {
07802 if (aa->description) {
07803
07804 int i;
07805 printapp = 1;
07806 for (i = 4; i < a->argc; i++) {
07807 if (!strcasestr(aa->description, a->argv[i])) {
07808 printapp = 0;
07809 } else {
07810 total_match++;
07811 }
07812 }
07813 }
07814 } else {
07815 printapp = 1;
07816 }
07817
07818 if (printapp) {
07819 ast_cli(a->fd," %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
07820 }
07821 }
07822 if ((!like) && (!describing)) {
07823 ast_cli(a->fd, " -= %d Applications Registered =-\n",total_apps);
07824 } else {
07825 ast_cli(a->fd, " -= %d Applications Matching =-\n",total_match);
07826 }
07827
07828 AST_RWLIST_UNLOCK(&apps);
07829
07830 return CLI_SUCCESS;
07831 }
07832
07833
07834
07835
07836 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
07837 int state)
07838 {
07839 struct ast_context *c = NULL;
07840 char *ret = NULL;
07841 int which = 0;
07842 int wordlen;
07843
07844
07845 if (pos != 2)
07846 return NULL;
07847
07848 ast_rdlock_contexts();
07849
07850 wordlen = strlen(word);
07851
07852
07853 while ( (c = ast_walk_contexts(c)) ) {
07854 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
07855 ret = ast_strdup(ast_get_context_name(c));
07856 break;
07857 }
07858 }
07859
07860 ast_unlock_contexts();
07861
07862 return ret;
07863 }
07864
07865
07866 struct dialplan_counters {
07867 int total_items;
07868 int total_context;
07869 int total_exten;
07870 int total_prio;
07871 int context_existence;
07872 int extension_existence;
07873 };
07874
07875
07876 static void print_ext(struct ast_exten *e, char * buf, int buflen)
07877 {
07878 int prio = ast_get_extension_priority(e);
07879 if (prio == PRIORITY_HINT) {
07880 snprintf(buf, buflen, "hint: %s",
07881 ast_get_extension_app(e));
07882 } else {
07883 snprintf(buf, buflen, "%d. %s(%s)",
07884 prio, ast_get_extension_app(e),
07885 (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
07886 }
07887 }
07888
07889
07890 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[])
07891 {
07892 struct ast_context *c = NULL;
07893 int res = 0, old_total_exten = dpc->total_exten;
07894
07895 ast_rdlock_contexts();
07896
07897
07898 while ( (c = ast_walk_contexts(c)) ) {
07899 struct ast_exten *e;
07900 struct ast_include *i;
07901 struct ast_ignorepat *ip;
07902 #ifndef LOW_MEMORY
07903 char buf[1024], buf2[1024];
07904 #else
07905 char buf[256], buf2[256];
07906 #endif
07907 int context_info_printed = 0;
07908
07909 if (context && strcmp(ast_get_context_name(c), context))
07910 continue;
07911
07912 dpc->context_existence = 1;
07913
07914 ast_rdlock_context(c);
07915
07916
07917
07918
07919
07920
07921
07922 if (!exten) {
07923 dpc->total_context++;
07924 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
07925 ast_get_context_name(c), ast_get_context_registrar(c));
07926 context_info_printed = 1;
07927 }
07928
07929
07930 e = NULL;
07931 while ( (e = ast_walk_context_extensions(c, e)) ) {
07932 struct ast_exten *p;
07933
07934 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
07935 continue;
07936
07937 dpc->extension_existence = 1;
07938
07939
07940 if (!context_info_printed) {
07941 dpc->total_context++;
07942 if (rinclude) {
07943 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
07944 ast_get_context_name(c), ast_get_context_registrar(c));
07945 } else {
07946 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
07947 ast_get_context_name(c), ast_get_context_registrar(c));
07948 }
07949 context_info_printed = 1;
07950 }
07951 dpc->total_prio++;
07952
07953
07954 if (e->matchcid == AST_EXT_MATCHCID_ON)
07955 snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
07956 else
07957 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
07958
07959 print_ext(e, buf2, sizeof(buf2));
07960
07961 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
07962 ast_get_extension_registrar(e));
07963
07964 dpc->total_exten++;
07965
07966 p = e;
07967 while ( (p = ast_walk_extension_priorities(e, p)) ) {
07968 const char *el = ast_get_extension_label(p);
07969 dpc->total_prio++;
07970 if (el)
07971 snprintf(buf, sizeof(buf), " [%s]", el);
07972 else
07973 buf[0] = '\0';
07974 print_ext(p, buf2, sizeof(buf2));
07975
07976 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
07977 ast_get_extension_registrar(p));
07978 }
07979 }
07980
07981
07982 i = NULL;
07983 while ( (i = ast_walk_context_includes(c, i)) ) {
07984 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
07985 if (exten) {
07986
07987 if (includecount >= AST_PBX_MAX_STACK) {
07988 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
07989 } else {
07990 int dupe = 0;
07991 int x;
07992 for (x = 0; x < includecount; x++) {
07993 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
07994 dupe++;
07995 break;
07996 }
07997 }
07998 if (!dupe) {
07999 includes[includecount] = ast_get_include_name(i);
08000 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
08001 } else {
08002 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
08003 }
08004 }
08005 } else {
08006 ast_cli(fd, " Include => %-45s [%s]\n",
08007 buf, ast_get_include_registrar(i));
08008 }
08009 }
08010
08011
08012 ip = NULL;
08013 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
08014 const char *ipname = ast_get_ignorepat_name(ip);
08015 char ignorepat[AST_MAX_EXTENSION];
08016 snprintf(buf, sizeof(buf), "'%s'", ipname);
08017 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
08018 if (!exten || ast_extension_match(ignorepat, exten)) {
08019 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
08020 buf, ast_get_ignorepat_registrar(ip));
08021 }
08022 }
08023 if (!rinclude) {
08024 struct ast_sw *sw = NULL;
08025 while ( (sw = ast_walk_context_switches(c, sw)) ) {
08026 snprintf(buf, sizeof(buf), "'%s/%s'",
08027 ast_get_switch_name(sw),
08028 ast_get_switch_data(sw));
08029 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
08030 buf, ast_get_switch_registrar(sw));
08031 }
08032 }
08033
08034 ast_unlock_context(c);
08035
08036
08037 if (context_info_printed)
08038 ast_cli(fd, "\n");
08039 }
08040 ast_unlock_contexts();
08041
08042 return (dpc->total_exten == old_total_exten) ? -1 : res;
08043 }
08044
08045 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[])
08046 {
08047 struct ast_context *c = NULL;
08048 int res = 0, old_total_exten = dpc->total_exten;
08049
08050 ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
08051
08052 ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
08053 ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
08054 ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
08055 ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
08056 ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
08057 ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
08058 ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
08059 ast_rdlock_contexts();
08060
08061
08062 while ( (c = ast_walk_contexts(c)) ) {
08063 int context_info_printed = 0;
08064
08065 if (context && strcmp(ast_get_context_name(c), context))
08066 continue;
08067
08068 dpc->context_existence = 1;
08069
08070 if (!c->pattern_tree) {
08071
08072 ast_exists_extension(NULL, c->name, "s", 1, "");
08073 }
08074
08075 ast_rdlock_context(c);
08076
08077 dpc->total_context++;
08078 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
08079 ast_get_context_name(c), ast_get_context_registrar(c));
08080 context_info_printed = 1;
08081
08082 if (c->pattern_tree)
08083 {
08084 cli_match_char_tree(c->pattern_tree, " ", fd);
08085 } else {
08086 ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
08087 }
08088
08089 ast_unlock_context(c);
08090
08091
08092 if (context_info_printed)
08093 ast_cli(fd, "\n");
08094 }
08095 ast_unlock_contexts();
08096
08097 return (dpc->total_exten == old_total_exten) ? -1 : res;
08098 }
08099
08100 static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08101 {
08102 char *exten = NULL, *context = NULL;
08103
08104 struct dialplan_counters counters;
08105 const char *incstack[AST_PBX_MAX_STACK];
08106
08107 switch (cmd) {
08108 case CLI_INIT:
08109 e->command = "dialplan show";
08110 e->usage =
08111 "Usage: dialplan show [[exten@]context]\n"
08112 " Show dialplan\n";
08113 return NULL;
08114 case CLI_GENERATE:
08115 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
08116 }
08117
08118 memset(&counters, 0, sizeof(counters));
08119
08120 if (a->argc != 2 && a->argc != 3)
08121 return CLI_SHOWUSAGE;
08122
08123
08124 if (a->argc == 3) {
08125 if (strchr(a->argv[2], '@')) {
08126 context = ast_strdupa(a->argv[2]);
08127 exten = strsep(&context, "@");
08128
08129 if (ast_strlen_zero(exten))
08130 exten = NULL;
08131 } else {
08132 context = ast_strdupa(a->argv[2]);
08133 }
08134 if (ast_strlen_zero(context))
08135 context = NULL;
08136 }
08137
08138 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
08139
08140
08141 if (context && !counters.context_existence) {
08142 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
08143 return CLI_FAILURE;
08144 }
08145
08146 if (exten && !counters.extension_existence) {
08147 if (context)
08148 ast_cli(a->fd, "There is no existence of %s@%s extension\n",
08149 exten, context);
08150 else
08151 ast_cli(a->fd,
08152 "There is no existence of '%s' extension in all contexts\n",
08153 exten);
08154 return CLI_FAILURE;
08155 }
08156
08157 ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
08158 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
08159 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
08160 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
08161
08162
08163 return CLI_SUCCESS;
08164 }
08165
08166
08167 static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08168 {
08169 char *exten = NULL, *context = NULL;
08170
08171 struct dialplan_counters counters;
08172 const char *incstack[AST_PBX_MAX_STACK];
08173
08174 switch (cmd) {
08175 case CLI_INIT:
08176 e->command = "dialplan debug";
08177 e->usage =
08178 "Usage: dialplan debug [context]\n"
08179 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
08180 return NULL;
08181 case CLI_GENERATE:
08182 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
08183 }
08184
08185 memset(&counters, 0, sizeof(counters));
08186
08187 if (a->argc != 2 && a->argc != 3)
08188 return CLI_SHOWUSAGE;
08189
08190
08191
08192 if (a->argc == 3) {
08193 if (strchr(a->argv[2], '@')) {
08194 context = ast_strdupa(a->argv[2]);
08195 exten = strsep(&context, "@");
08196
08197 if (ast_strlen_zero(exten))
08198 exten = NULL;
08199 } else {
08200 context = ast_strdupa(a->argv[2]);
08201 }
08202 if (ast_strlen_zero(context))
08203 context = NULL;
08204 }
08205
08206 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
08207
08208
08209 if (context && !counters.context_existence) {
08210 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
08211 return CLI_FAILURE;
08212 }
08213
08214
08215 ast_cli(a->fd,"-= %d %s. =-\n",
08216 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
08217
08218
08219 return CLI_SUCCESS;
08220 }
08221
08222
08223 static void manager_dpsendack(struct mansession *s, const struct message *m)
08224 {
08225 astman_send_listack(s, m, "DialPlan list will follow", "start");
08226 }
08227
08228
08229
08230
08231
08232 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
08233 const char *actionidtext, const char *context,
08234 const char *exten, struct dialplan_counters *dpc,
08235 struct ast_include *rinclude)
08236 {
08237 struct ast_context *c;
08238 int res = 0, old_total_exten = dpc->total_exten;
08239
08240 if (ast_strlen_zero(exten))
08241 exten = NULL;
08242 if (ast_strlen_zero(context))
08243 context = NULL;
08244
08245 ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
08246
08247
08248 if (ast_rdlock_contexts()) {
08249 astman_send_error(s, m, "Failed to lock contexts");
08250 ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
08251 return -1;
08252 }
08253
08254 c = NULL;
08255 while ( (c = ast_walk_contexts(c)) ) {
08256 struct ast_exten *e;
08257 struct ast_include *i;
08258 struct ast_ignorepat *ip;
08259
08260 if (context && strcmp(ast_get_context_name(c), context) != 0)
08261 continue;
08262
08263 dpc->context_existence = 1;
08264 dpc->total_context++;
08265
08266 ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
08267
08268 if (ast_rdlock_context(c)) {
08269 ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
08270 continue;
08271 }
08272
08273
08274 e = NULL;
08275 while ( (e = ast_walk_context_extensions(c, e)) ) {
08276 struct ast_exten *p;
08277
08278
08279 if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
08280
08281 ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
08282 continue;
08283 }
08284 ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
08285
08286 dpc->extension_existence = 1;
08287
08288 dpc->total_exten++;
08289
08290 p = NULL;
08291 while ( (p = ast_walk_extension_priorities(e, p)) ) {
08292 int prio = ast_get_extension_priority(p);
08293
08294 dpc->total_prio++;
08295 if (!dpc->total_items++)
08296 manager_dpsendack(s, m);
08297 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
08298 astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
08299
08300
08301 if (ast_get_extension_label(p))
08302 astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
08303
08304 if (prio == PRIORITY_HINT) {
08305 astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
08306 } else {
08307 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));
08308 }
08309 astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
08310 }
08311 }
08312
08313 i = NULL;
08314 while ( (i = ast_walk_context_includes(c, i)) ) {
08315 if (exten) {
08316
08317 manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
08318 } else {
08319 if (!dpc->total_items++)
08320 manager_dpsendack(s, m);
08321 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
08322 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));
08323 astman_append(s, "\r\n");
08324 ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
08325 }
08326 }
08327
08328 ip = NULL;
08329 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
08330 const char *ipname = ast_get_ignorepat_name(ip);
08331 char ignorepat[AST_MAX_EXTENSION];
08332
08333 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
08334 if (!exten || ast_extension_match(ignorepat, exten)) {
08335 if (!dpc->total_items++)
08336 manager_dpsendack(s, m);
08337 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
08338 astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
08339 astman_append(s, "\r\n");
08340 }
08341 }
08342 if (!rinclude) {
08343 struct ast_sw *sw = NULL;
08344 while ( (sw = ast_walk_context_switches(c, sw)) ) {
08345 if (!dpc->total_items++)
08346 manager_dpsendack(s, m);
08347 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
08348 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));
08349 astman_append(s, "\r\n");
08350 ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
08351 }
08352 }
08353
08354 ast_unlock_context(c);
08355 }
08356 ast_unlock_contexts();
08357
08358 if (dpc->total_exten == old_total_exten) {
08359 ast_debug(3, "manager_show_dialplan: Found nothing new\n");
08360
08361 return -1;
08362 } else {
08363 return res;
08364 }
08365 }
08366
08367
08368 static int manager_show_dialplan(struct mansession *s, const struct message *m)
08369 {
08370 const char *exten, *context;
08371 const char *id = astman_get_header(m, "ActionID");
08372 char idtext[256];
08373
08374
08375 struct dialplan_counters counters;
08376
08377 if (!ast_strlen_zero(id))
08378 snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
08379 else
08380 idtext[0] = '\0';
08381
08382 memset(&counters, 0, sizeof(counters));
08383
08384 exten = astman_get_header(m, "Extension");
08385 context = astman_get_header(m, "Context");
08386
08387 manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
08388
08389 if (!ast_strlen_zero(context) && !counters.context_existence) {
08390 char errorbuf[BUFSIZ];
08391
08392 snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
08393 astman_send_error(s, m, errorbuf);
08394 return 0;
08395 }
08396 if (!ast_strlen_zero(exten) && !counters.extension_existence) {
08397 char errorbuf[BUFSIZ];
08398
08399 if (!ast_strlen_zero(context))
08400 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
08401 else
08402 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
08403 astman_send_error(s, m, errorbuf);
08404 return 0;
08405 }
08406
08407 if (!counters.total_items) {
08408 manager_dpsendack(s, m);
08409 }
08410
08411 astman_append(s, "Event: ShowDialPlanComplete\r\n"
08412 "EventList: Complete\r\n"
08413 "ListItems: %d\r\n"
08414 "ListExtensions: %d\r\n"
08415 "ListPriorities: %d\r\n"
08416 "ListContexts: %d\r\n"
08417 "%s"
08418 "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
08419
08420
08421 return 0;
08422 }
08423
08424
08425 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08426 {
08427 int i = 0;
08428 struct ast_var_t *newvariable;
08429
08430 switch (cmd) {
08431 case CLI_INIT:
08432 e->command = "dialplan show globals";
08433 e->usage =
08434 "Usage: dialplan show globals\n"
08435 " List current global dialplan variables and their values\n";
08436 return NULL;
08437 case CLI_GENERATE:
08438 return NULL;
08439 }
08440
08441 ast_rwlock_rdlock(&globalslock);
08442 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
08443 i++;
08444 ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
08445 }
08446 ast_rwlock_unlock(&globalslock);
08447 ast_cli(a->fd, "\n -- %d variable(s)\n", i);
08448
08449 return CLI_SUCCESS;
08450 }
08451
08452 #ifdef AST_DEVMODE
08453 static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08454 {
08455 struct ast_devstate_aggregate agg;
08456 int i, j, exten, combined;
08457
08458 switch (cmd) {
08459 case CLI_INIT:
08460 e->command = "core show device2extenstate";
08461 e->usage =
08462 "Usage: core show device2extenstate\n"
08463 " Lists device state to extension state combinations.\n";
08464 case CLI_GENERATE:
08465 return NULL;
08466 }
08467 for (i = 0; i < AST_DEVICE_TOTAL; i++) {
08468 for (j = 0; j < AST_DEVICE_TOTAL; j++) {
08469 ast_devstate_aggregate_init(&agg);
08470 ast_devstate_aggregate_add(&agg, i);
08471 ast_devstate_aggregate_add(&agg, j);
08472 combined = ast_devstate_aggregate_result(&agg);
08473 exten = ast_devstate_to_extenstate(combined);
08474 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));
08475 }
08476 }
08477 ast_cli(a->fd, "\n");
08478 return CLI_SUCCESS;
08479 }
08480 #endif
08481
08482
08483 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08484 {
08485 struct ast_channel *chan = NULL;
08486 struct ast_str *vars = ast_str_alloca(BUFSIZ * 4);
08487
08488 switch (cmd) {
08489 case CLI_INIT:
08490 e->command = "dialplan show chanvar";
08491 e->usage =
08492 "Usage: dialplan show chanvar <channel>\n"
08493 " List current channel variables and their values\n";
08494 return NULL;
08495 case CLI_GENERATE:
08496 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
08497 }
08498
08499 if (a->argc != e->args + 1)
08500 return CLI_SHOWUSAGE;
08501
08502 if (!(chan = ast_channel_get_by_name(a->argv[e->args]))) {
08503 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
08504 return CLI_FAILURE;
08505 }
08506
08507 pbx_builtin_serialize_variables(chan, &vars);
08508
08509 if (ast_str_strlen(vars)) {
08510 ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
08511 }
08512
08513 chan = ast_channel_unref(chan);
08514
08515 return CLI_SUCCESS;
08516 }
08517
08518 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08519 {
08520 switch (cmd) {
08521 case CLI_INIT:
08522 e->command = "dialplan set global";
08523 e->usage =
08524 "Usage: dialplan set global <name> <value>\n"
08525 " Set global dialplan variable <name> to <value>\n";
08526 return NULL;
08527 case CLI_GENERATE:
08528 return NULL;
08529 }
08530
08531 if (a->argc != e->args + 2)
08532 return CLI_SHOWUSAGE;
08533
08534 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
08535 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
08536
08537 return CLI_SUCCESS;
08538 }
08539
08540 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08541 {
08542 struct ast_channel *chan;
08543 const char *chan_name, *var_name, *var_value;
08544
08545 switch (cmd) {
08546 case CLI_INIT:
08547 e->command = "dialplan set chanvar";
08548 e->usage =
08549 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
08550 " Set channel variable <varname> to <value>\n";
08551 return NULL;
08552 case CLI_GENERATE:
08553 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
08554 }
08555
08556 if (a->argc != e->args + 3)
08557 return CLI_SHOWUSAGE;
08558
08559 chan_name = a->argv[e->args];
08560 var_name = a->argv[e->args + 1];
08561 var_value = a->argv[e->args + 2];
08562
08563 if (!(chan = ast_channel_get_by_name(chan_name))) {
08564 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
08565 return CLI_FAILURE;
08566 }
08567
08568 pbx_builtin_setvar_helper(chan, var_name, var_value);
08569
08570 chan = ast_channel_unref(chan);
08571
08572 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
08573
08574 return CLI_SUCCESS;
08575 }
08576
08577 static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08578 {
08579 int oldval = 0;
08580
08581 switch (cmd) {
08582 case CLI_INIT:
08583 e->command = "dialplan set extenpatternmatchnew true";
08584 e->usage =
08585 "Usage: dialplan set extenpatternmatchnew true|false\n"
08586 " Use the NEW extension pattern matching algorithm, true or false.\n";
08587 return NULL;
08588 case CLI_GENERATE:
08589 return NULL;
08590 }
08591
08592 if (a->argc != 4)
08593 return CLI_SHOWUSAGE;
08594
08595 oldval = pbx_set_extenpatternmatchnew(1);
08596
08597 if (oldval)
08598 ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
08599 else
08600 ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
08601
08602 return CLI_SUCCESS;
08603 }
08604
08605 static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08606 {
08607 int oldval = 0;
08608
08609 switch (cmd) {
08610 case CLI_INIT:
08611 e->command = "dialplan set extenpatternmatchnew false";
08612 e->usage =
08613 "Usage: dialplan set extenpatternmatchnew true|false\n"
08614 " Use the NEW extension pattern matching algorithm, true or false.\n";
08615 return NULL;
08616 case CLI_GENERATE:
08617 return NULL;
08618 }
08619
08620 if (a->argc != 4)
08621 return CLI_SHOWUSAGE;
08622
08623 oldval = pbx_set_extenpatternmatchnew(0);
08624
08625 if (!oldval)
08626 ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
08627 else
08628 ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
08629
08630 return CLI_SUCCESS;
08631 }
08632
08633
08634
08635
08636 static struct ast_cli_entry pbx_cli[] = {
08637 AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
08638 AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
08639 AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
08640 AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
08641 AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
08642 AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
08643 #ifdef AST_DEVMODE
08644 AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
08645 #endif
08646 AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
08647 AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
08648 AST_CLI_DEFINE(handle_show_hangup_all, "Show hangup handlers of all channels"),
08649 AST_CLI_DEFINE(handle_show_hangup_channel, "Show hangup handlers of a specified channel"),
08650 AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
08651 AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
08652 AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
08653 AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
08654 AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
08655 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
08656 AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
08657 };
08658
08659 static void unreference_cached_app(struct ast_app *app)
08660 {
08661 struct ast_context *context = NULL;
08662 struct ast_exten *eroot = NULL, *e = NULL;
08663
08664 ast_rdlock_contexts();
08665 while ((context = ast_walk_contexts(context))) {
08666 while ((eroot = ast_walk_context_extensions(context, eroot))) {
08667 while ((e = ast_walk_extension_priorities(eroot, e))) {
08668 if (e->cached_app == app)
08669 e->cached_app = NULL;
08670 }
08671 }
08672 }
08673 ast_unlock_contexts();
08674
08675 return;
08676 }
08677
08678 int ast_unregister_application(const char *app)
08679 {
08680 struct ast_app *tmp;
08681
08682 AST_RWLIST_WRLOCK(&apps);
08683 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
08684 if (!strcasecmp(app, tmp->name)) {
08685 unreference_cached_app(tmp);
08686 AST_RWLIST_REMOVE_CURRENT(list);
08687 ast_verb(2, "Unregistered application '%s'\n", tmp->name);
08688 ast_string_field_free_memory(tmp);
08689 ast_free(tmp);
08690 break;
08691 }
08692 }
08693 AST_RWLIST_TRAVERSE_SAFE_END;
08694 AST_RWLIST_UNLOCK(&apps);
08695
08696 return tmp ? 0 : -1;
08697 }
08698
08699 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
08700 {
08701 struct ast_context *tmp, **local_contexts;
08702 struct fake_context search;
08703 int length = sizeof(struct ast_context) + strlen(name) + 1;
08704
08705 if (!contexts_table) {
08706
08707 ast_wrlock_contexts();
08708 if (!contexts_table) {
08709 contexts_table = ast_hashtab_create(17,
08710 ast_hashtab_compare_contexts,
08711 ast_hashtab_resize_java,
08712 ast_hashtab_newsize_java,
08713 ast_hashtab_hash_contexts,
08714 0);
08715 }
08716 ast_unlock_contexts();
08717 }
08718
08719 ast_copy_string(search.name, name, sizeof(search.name));
08720 if (!extcontexts) {
08721 ast_rdlock_contexts();
08722 local_contexts = &contexts;
08723 tmp = ast_hashtab_lookup(contexts_table, &search);
08724 ast_unlock_contexts();
08725 if (tmp) {
08726 tmp->refcount++;
08727 return tmp;
08728 }
08729 } else {
08730 local_contexts = extcontexts;
08731 tmp = ast_hashtab_lookup(exttable, &search);
08732 if (tmp) {
08733 tmp->refcount++;
08734 return tmp;
08735 }
08736 }
08737
08738 if ((tmp = ast_calloc(1, length))) {
08739 ast_rwlock_init(&tmp->lock);
08740 ast_mutex_init(&tmp->macrolock);
08741 strcpy(tmp->name, name);
08742 tmp->root = NULL;
08743 tmp->root_table = NULL;
08744 tmp->registrar = ast_strdup(registrar);
08745 tmp->includes = NULL;
08746 tmp->ignorepats = NULL;
08747 tmp->refcount = 1;
08748 } else {
08749 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
08750 return NULL;
08751 }
08752
08753 if (!extcontexts) {
08754 ast_wrlock_contexts();
08755 tmp->next = *local_contexts;
08756 *local_contexts = tmp;
08757 ast_hashtab_insert_safe(contexts_table, tmp);
08758 ast_unlock_contexts();
08759 ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
08760 ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
08761 } else {
08762 tmp->next = *local_contexts;
08763 if (exttable)
08764 ast_hashtab_insert_immediate(exttable, tmp);
08765
08766 *local_contexts = tmp;
08767 ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
08768 ast_verb(3, "Registered extension context '%s'; registrar: %s\n", tmp->name, registrar);
08769 }
08770 return tmp;
08771 }
08772
08773 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
08774
08775 struct store_hint {
08776 char *context;
08777 char *exten;
08778 AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
08779 int laststate;
08780 int last_presence_state;
08781 char *last_presence_subtype;
08782 char *last_presence_message;
08783
08784 AST_LIST_ENTRY(store_hint) list;
08785 char data[1];
08786 };
08787
08788 AST_LIST_HEAD_NOLOCK(store_hints, store_hint);
08789
08790 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
08791 {
08792 struct ast_include *i;
08793 struct ast_ignorepat *ip;
08794 struct ast_sw *sw;
08795
08796 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);
08797
08798
08799 for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
08800 if (strcmp(ast_get_include_registrar(i), registrar) == 0)
08801 continue;
08802 ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
08803 }
08804
08805
08806 for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
08807 if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
08808 continue;
08809 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));
08810 }
08811
08812
08813 for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
08814 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
08815 continue;
08816 ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
08817 }
08818 }
08819
08820
08821
08822
08823 static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
08824 {
08825 struct ast_context *new = ast_hashtab_lookup(exttable, context);
08826 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
08827 struct ast_hashtab_iter *exten_iter;
08828 struct ast_hashtab_iter *prio_iter;
08829 int insert_count = 0;
08830 int first = 1;
08831
08832
08833
08834
08835
08836
08837 if (context->root_table) {
08838 exten_iter = ast_hashtab_start_traversal(context->root_table);
08839 while ((exten_item=ast_hashtab_next(exten_iter))) {
08840 if (new) {
08841 new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
08842 } else {
08843 new_exten_item = NULL;
08844 }
08845 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
08846 while ((prio_item=ast_hashtab_next(prio_iter))) {
08847 int res1;
08848 char *dupdstr;
08849
08850 if (new_exten_item) {
08851 new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
08852 } else {
08853 new_prio_item = NULL;
08854 }
08855 if (strcmp(prio_item->registrar,registrar) == 0) {
08856 continue;
08857 }
08858
08859 if (!new) {
08860 new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar);
08861 }
08862
08863
08864 if (first) {
08865 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
08866 first = 0;
08867 }
08868
08869 if (!new) {
08870 ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
08871 ast_hashtab_end_traversal(prio_iter);
08872 ast_hashtab_end_traversal(exten_iter);
08873 return;
08874 }
08875
08876
08877
08878 dupdstr = ast_strdup(prio_item->data);
08879
08880 res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
08881 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
08882 if (!res1 && new_exten_item && new_prio_item){
08883 ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
08884 context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
08885 } else {
08886
08887
08888 insert_count++;
08889 }
08890 }
08891 ast_hashtab_end_traversal(prio_iter);
08892 }
08893 ast_hashtab_end_traversal(exten_iter);
08894 }
08895
08896 if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
08897 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
08898
08899
08900 new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
08901
08902
08903 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
08904 }
08905 }
08906
08907
08908
08909 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
08910 {
08911 double ft;
08912 struct ast_context *tmp;
08913 struct ast_context *oldcontextslist;
08914 struct ast_hashtab *oldtable;
08915 struct store_hints hints_stored = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
08916 struct store_hints hints_removed = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
08917 struct store_hint *saved_hint;
08918 struct ast_hint *hint;
08919 struct ast_exten *exten;
08920 int length;
08921 struct ast_state_cb *thiscb;
08922 struct ast_hashtab_iter *iter;
08923 struct ao2_iterator i;
08924 struct timeval begintime;
08925 struct timeval writelocktime;
08926 struct timeval endlocktime;
08927 struct timeval enddeltime;
08928
08929
08930
08931
08932
08933
08934
08935
08936
08937
08938
08939
08940
08941 begintime = ast_tvnow();
08942 ast_mutex_lock(&context_merge_lock);
08943 ast_wrlock_contexts();
08944
08945 if (!contexts_table) {
08946
08947 contexts_table = exttable;
08948 contexts = *extcontexts;
08949 ast_unlock_contexts();
08950 ast_mutex_unlock(&context_merge_lock);
08951 return;
08952 }
08953
08954 iter = ast_hashtab_start_traversal(contexts_table);
08955 while ((tmp = ast_hashtab_next(iter))) {
08956 context_merge(extcontexts, exttable, tmp, registrar);
08957 }
08958 ast_hashtab_end_traversal(iter);
08959
08960 ao2_lock(hints);
08961 writelocktime = ast_tvnow();
08962
08963
08964 i = ao2_iterator_init(hints, AO2_ITERATOR_DONTLOCK);
08965 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
08966 if (ao2_container_count(hint->callbacks)) {
08967 ao2_lock(hint);
08968 if (!hint->exten) {
08969
08970 ao2_unlock(hint);
08971 continue;
08972 }
08973
08974 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2
08975 + sizeof(*saved_hint);
08976 if (!(saved_hint = ast_calloc(1, length))) {
08977 ao2_unlock(hint);
08978 continue;
08979 }
08980
08981
08982 while ((thiscb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
08983 AST_LIST_INSERT_TAIL(&saved_hint->callbacks, thiscb, entry);
08984
08985
08986
08987
08988 }
08989
08990 saved_hint->laststate = hint->laststate;
08991 saved_hint->context = saved_hint->data;
08992 strcpy(saved_hint->data, hint->exten->parent->name);
08993 saved_hint->exten = saved_hint->data + strlen(saved_hint->context) + 1;
08994 strcpy(saved_hint->exten, hint->exten->exten);
08995 if (hint->last_presence_subtype) {
08996 saved_hint->last_presence_subtype = ast_strdup(hint->last_presence_subtype);
08997 }
08998 if (hint->last_presence_message) {
08999 saved_hint->last_presence_message = ast_strdup(hint->last_presence_message);
09000 }
09001 saved_hint->last_presence_state = hint->last_presence_state;
09002 ao2_unlock(hint);
09003 AST_LIST_INSERT_HEAD(&hints_stored, saved_hint, list);
09004 }
09005 }
09006 ao2_iterator_destroy(&i);
09007
09008
09009 oldtable = contexts_table;
09010 oldcontextslist = contexts;
09011
09012
09013 contexts_table = exttable;
09014 contexts = *extcontexts;
09015
09016
09017
09018
09019
09020 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_stored, list))) {
09021 struct pbx_find_info q = { .stacklen = 0 };
09022
09023 exten = pbx_find_extension(NULL, NULL, &q, saved_hint->context, saved_hint->exten,
09024 PRIORITY_HINT, NULL, "", E_MATCH);
09025
09026
09027
09028
09029
09030 if (exten && exten->exten[0] == '_') {
09031 ast_add_extension_nolock(exten->parent->name, 0, saved_hint->exten,
09032 PRIORITY_HINT, NULL, 0, exten->app, ast_strdup(exten->data), ast_free_ptr,
09033 exten->registrar);
09034
09035 exten = ast_hint_extension_nolock(NULL, saved_hint->context,
09036 saved_hint->exten);
09037 }
09038
09039
09040 hint = exten ? ao2_find(hints, exten, 0) : NULL;
09041 if (!hint) {
09042
09043
09044
09045
09046 AST_LIST_INSERT_HEAD(&hints_removed, saved_hint, list);
09047 } else {
09048 ao2_lock(hint);
09049 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
09050 ao2_link(hint->callbacks, thiscb);
09051
09052 ao2_ref(thiscb, -1);
09053 }
09054 hint->laststate = saved_hint->laststate;
09055 hint->last_presence_state = saved_hint->last_presence_state;
09056 hint->last_presence_subtype = saved_hint->last_presence_subtype;
09057 hint->last_presence_message = saved_hint->last_presence_message;
09058 ao2_unlock(hint);
09059 ao2_ref(hint, -1);
09060
09061
09062
09063
09064 ast_free(saved_hint);
09065 }
09066 }
09067
09068 ao2_unlock(hints);
09069 ast_unlock_contexts();
09070
09071
09072
09073
09074
09075 while ((saved_hint = AST_LIST_REMOVE_HEAD(&hints_removed, list))) {
09076
09077 while ((thiscb = AST_LIST_REMOVE_HEAD(&saved_hint->callbacks, entry))) {
09078 execute_state_callback(thiscb->change_cb,
09079 saved_hint->context,
09080 saved_hint->exten,
09081 thiscb->data,
09082 AST_HINT_UPDATE_DEVICE,
09083 NULL,
09084 NULL);
09085
09086 ao2_ref(thiscb, -1);
09087 }
09088 ast_free(saved_hint->last_presence_subtype);
09089 ast_free(saved_hint->last_presence_message);
09090 ast_free(saved_hint);
09091 }
09092
09093 ast_mutex_unlock(&context_merge_lock);
09094 endlocktime = ast_tvnow();
09095
09096
09097
09098
09099
09100
09101
09102 ast_hashtab_destroy(oldtable, NULL);
09103
09104 for (tmp = oldcontextslist; tmp; ) {
09105 struct ast_context *next;
09106
09107 next = tmp->next;
09108 __ast_internal_context_destroy(tmp);
09109 tmp = next;
09110 }
09111 enddeltime = ast_tvnow();
09112
09113 ft = ast_tvdiff_us(writelocktime, begintime);
09114 ft /= 1000000.0;
09115 ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
09116
09117 ft = ast_tvdiff_us(endlocktime, writelocktime);
09118 ft /= 1000000.0;
09119 ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
09120
09121 ft = ast_tvdiff_us(enddeltime, endlocktime);
09122 ft /= 1000000.0;
09123 ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
09124
09125 ft = ast_tvdiff_us(enddeltime, begintime);
09126 ft /= 1000000.0;
09127 ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
09128 }
09129
09130
09131
09132
09133
09134
09135 int ast_context_add_include(const char *context, const char *include, const char *registrar)
09136 {
09137 int ret = -1;
09138 struct ast_context *c;
09139
09140 c = find_context_locked(context);
09141 if (c) {
09142 ret = ast_context_add_include2(c, include, registrar);
09143 ast_unlock_contexts();
09144 }
09145 return ret;
09146 }
09147
09148
09149
09150
09151
09152 static int lookup_name(const char *s, const char * const names[], int max)
09153 {
09154 int i;
09155
09156 if (names && *s > '9') {
09157 for (i = 0; names[i]; i++) {
09158 if (!strcasecmp(s, names[i])) {
09159 return i;
09160 }
09161 }
09162 }
09163
09164
09165 if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
09166
09167 return i - 1;
09168 }
09169 return -1;
09170 }
09171
09172
09173
09174
09175 static unsigned get_range(char *src, int max, const char * const names[], const char *msg)
09176 {
09177 int start, end;
09178 unsigned int mask = 0;
09179 char *part;
09180
09181
09182 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
09183 return (1 << max) - 1;
09184 }
09185
09186 while ((part = strsep(&src, "&"))) {
09187
09188 char *endpart = strchr(part, '-');
09189 if (endpart) {
09190 *endpart++ = '\0';
09191 }
09192
09193 if ((start = lookup_name(part, names, max)) < 0) {
09194 ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
09195 continue;
09196 }
09197 if (endpart) {
09198 if ((end = lookup_name(endpart, names, max)) < 0) {
09199 ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
09200 continue;
09201 }
09202 } else {
09203 end = start;
09204 }
09205
09206 mask |= (1 << end);
09207 while (start != end) {
09208 mask |= (1 << start);
09209 if (++start >= max) {
09210 start = 0;
09211 }
09212 }
09213 }
09214 return mask;
09215 }
09216
09217
09218 static void get_timerange(struct ast_timing *i, char *times)
09219 {
09220 char *endpart, *part;
09221 int x;
09222 int st_h, st_m;
09223 int endh, endm;
09224 int minute_start, minute_end;
09225
09226
09227 memset(i->minmask, 0, sizeof(i->minmask));
09228
09229
09230
09231 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
09232
09233 for (x = 0; x < 48; x++) {
09234 i->minmask[x] = 0x3fffffff;
09235 }
09236 return;
09237 }
09238
09239 while ((part = strsep(×, "&"))) {
09240 if (!(endpart = strchr(part, '-'))) {
09241 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
09242 ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
09243 continue;
09244 }
09245 i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
09246 continue;
09247 }
09248 *endpart++ = '\0';
09249
09250 while (*endpart && !isdigit(*endpart)) {
09251 endpart++;
09252 }
09253 if (!*endpart) {
09254 ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
09255 continue;
09256 }
09257 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
09258 ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
09259 continue;
09260 }
09261 if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
09262 ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
09263 continue;
09264 }
09265 minute_start = st_h * 60 + st_m;
09266 minute_end = endh * 60 + endm;
09267
09268 for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
09269 i->minmask[x / 30] |= (1 << (x % 30));
09270 }
09271
09272 i->minmask[x / 30] |= (1 << (x % 30));
09273 }
09274
09275 return;
09276 }
09277
09278 static const char * const days[] =
09279 {
09280 "sun",
09281 "mon",
09282 "tue",
09283 "wed",
09284 "thu",
09285 "fri",
09286 "sat",
09287 NULL,
09288 };
09289
09290 static const char * const months[] =
09291 {
09292 "jan",
09293 "feb",
09294 "mar",
09295 "apr",
09296 "may",
09297 "jun",
09298 "jul",
09299 "aug",
09300 "sep",
09301 "oct",
09302 "nov",
09303 "dec",
09304 NULL,
09305 };
09306
09307 int ast_build_timing(struct ast_timing *i, const char *info_in)
09308 {
09309 char *info;
09310 int j, num_fields, last_sep = -1;
09311
09312 i->timezone = NULL;
09313
09314
09315 if (ast_strlen_zero(info_in)) {
09316 return 0;
09317 }
09318
09319
09320 info = ast_strdupa(info_in);
09321
09322
09323 for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
09324 if (info[j] == ',') {
09325 last_sep = j;
09326 num_fields++;
09327 }
09328 }
09329
09330
09331 if (num_fields == 5) {
09332 i->timezone = ast_strdup(info + last_sep + 1);
09333 }
09334
09335
09336 i->monthmask = 0xfff;
09337 i->daymask = 0x7fffffffU;
09338 i->dowmask = 0x7f;
09339
09340 get_timerange(i, strsep(&info, "|,"));
09341 if (info)
09342 i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
09343 if (info)
09344 i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
09345 if (info)
09346 i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
09347 return 1;
09348 }
09349
09350 int ast_check_timing(const struct ast_timing *i)
09351 {
09352 return ast_check_timing2(i, ast_tvnow());
09353 }
09354
09355 int ast_check_timing2(const struct ast_timing *i, const struct timeval tv)
09356 {
09357 struct ast_tm tm;
09358
09359 ast_localtime(&tv, &tm, i->timezone);
09360
09361
09362 if (!(i->monthmask & (1 << tm.tm_mon)))
09363 return 0;
09364
09365
09366
09367 if (!(i->daymask & (1 << (tm.tm_mday-1))))
09368 return 0;
09369
09370
09371 if (!(i->dowmask & (1 << tm.tm_wday)))
09372 return 0;
09373
09374
09375 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
09376 ast_log(LOG_WARNING, "Insane time...\n");
09377 return 0;
09378 }
09379
09380
09381
09382 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))))
09383 return 0;
09384
09385
09386 return 1;
09387 }
09388
09389 int ast_destroy_timing(struct ast_timing *i)
09390 {
09391 if (i->timezone) {
09392 ast_free(i->timezone);
09393 i->timezone = NULL;
09394 }
09395 return 0;
09396 }
09397
09398
09399
09400
09401
09402
09403
09404 int ast_context_add_include2(struct ast_context *con, const char *value,
09405 const char *registrar)
09406 {
09407 struct ast_include *new_include;
09408 char *c;
09409 struct ast_include *i, *il = NULL;
09410 int length;
09411 char *p;
09412
09413 length = sizeof(struct ast_include);
09414 length += 2 * (strlen(value) + 1);
09415
09416
09417 if (!(new_include = ast_calloc(1, length)))
09418 return -1;
09419
09420
09421
09422 p = new_include->stuff;
09423 new_include->name = p;
09424 strcpy(p, value);
09425 p += strlen(value) + 1;
09426 new_include->rname = p;
09427 strcpy(p, value);
09428
09429 if ( (c = strchr(p, ',')) ) {
09430 *c++ = '\0';
09431 new_include->hastime = ast_build_timing(&(new_include->timing), c);
09432 }
09433 new_include->next = NULL;
09434 new_include->registrar = registrar;
09435
09436 ast_wrlock_context(con);
09437
09438
09439 for (i = con->includes; i; i = i->next) {
09440 if (!strcasecmp(i->name, new_include->name)) {
09441 ast_destroy_timing(&(new_include->timing));
09442 ast_free(new_include);
09443 ast_unlock_context(con);
09444 errno = EEXIST;
09445 return -1;
09446 }
09447 il = i;
09448 }
09449
09450
09451 if (il)
09452 il->next = new_include;
09453 else
09454 con->includes = new_include;
09455 ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
09456
09457 ast_unlock_context(con);
09458
09459 return 0;
09460 }
09461
09462
09463
09464
09465
09466
09467 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
09468 {
09469 int ret = -1;
09470 struct ast_context *c;
09471
09472 c = find_context_locked(context);
09473 if (c) {
09474 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
09475 ast_unlock_contexts();
09476 }
09477 return ret;
09478 }
09479
09480
09481
09482
09483
09484
09485
09486
09487 int ast_context_add_switch2(struct ast_context *con, const char *value,
09488 const char *data, int eval, const char *registrar)
09489 {
09490 struct ast_sw *new_sw;
09491 struct ast_sw *i;
09492 int length;
09493 char *p;
09494
09495 length = sizeof(struct ast_sw);
09496 length += strlen(value) + 1;
09497 if (data)
09498 length += strlen(data);
09499 length++;
09500
09501
09502 if (!(new_sw = ast_calloc(1, length)))
09503 return -1;
09504
09505 p = new_sw->stuff;
09506 new_sw->name = p;
09507 strcpy(new_sw->name, value);
09508 p += strlen(value) + 1;
09509 new_sw->data = p;
09510 if (data) {
09511 strcpy(new_sw->data, data);
09512 p += strlen(data) + 1;
09513 } else {
09514 strcpy(new_sw->data, "");
09515 p++;
09516 }
09517 new_sw->eval = eval;
09518 new_sw->registrar = registrar;
09519
09520
09521 ast_wrlock_context(con);
09522
09523
09524 AST_LIST_TRAVERSE(&con->alts, i, list) {
09525 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
09526 ast_free(new_sw);
09527 ast_unlock_context(con);
09528 errno = EEXIST;
09529 return -1;
09530 }
09531 }
09532
09533
09534 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
09535
09536 ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
09537
09538 ast_unlock_context(con);
09539
09540 return 0;
09541 }
09542
09543
09544
09545
09546
09547 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
09548 {
09549 int ret = -1;
09550 struct ast_context *c;
09551
09552 c = find_context_locked(context);
09553 if (c) {
09554 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
09555 ast_unlock_contexts();
09556 }
09557 return ret;
09558 }
09559
09560 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
09561 {
09562 struct ast_ignorepat *ip, *ipl = NULL;
09563
09564 ast_wrlock_context(con);
09565
09566 for (ip = con->ignorepats; ip; ip = ip->next) {
09567 if (!strcmp(ip->pattern, ignorepat) &&
09568 (!registrar || (registrar == ip->registrar))) {
09569 if (ipl) {
09570 ipl->next = ip->next;
09571 ast_free(ip);
09572 } else {
09573 con->ignorepats = ip->next;
09574 ast_free(ip);
09575 }
09576 ast_unlock_context(con);
09577 return 0;
09578 }
09579 ipl = ip;
09580 }
09581
09582 ast_unlock_context(con);
09583 errno = EINVAL;
09584 return -1;
09585 }
09586
09587
09588
09589
09590
09591 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
09592 {
09593 int ret = -1;
09594 struct ast_context *c;
09595
09596 c = find_context_locked(context);
09597 if (c) {
09598 ret = ast_context_add_ignorepat2(c, value, registrar);
09599 ast_unlock_contexts();
09600 }
09601 return ret;
09602 }
09603
09604 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
09605 {
09606 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
09607 int length;
09608 char *pattern;
09609 length = sizeof(struct ast_ignorepat);
09610 length += strlen(value) + 1;
09611 if (!(ignorepat = ast_calloc(1, length)))
09612 return -1;
09613
09614
09615
09616
09617
09618
09619 pattern = (char *) ignorepat->pattern;
09620 strcpy(pattern, value);
09621 ignorepat->next = NULL;
09622 ignorepat->registrar = registrar;
09623 ast_wrlock_context(con);
09624 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
09625 ignorepatl = ignorepatc;
09626 if (!strcasecmp(ignorepatc->pattern, value)) {
09627
09628 ast_unlock_context(con);
09629 ast_free(ignorepat);
09630 errno = EEXIST;
09631 return -1;
09632 }
09633 }
09634 if (ignorepatl)
09635 ignorepatl->next = ignorepat;
09636 else
09637 con->ignorepats = ignorepat;
09638 ast_unlock_context(con);
09639 return 0;
09640
09641 }
09642
09643 int ast_ignore_pattern(const char *context, const char *pattern)
09644 {
09645 struct ast_context *con = ast_context_find(context);
09646
09647 if (con) {
09648 struct ast_ignorepat *pat;
09649
09650 for (pat = con->ignorepats; pat; pat = pat->next) {
09651 if (ast_extension_match(pat->pattern, pattern))
09652 return 1;
09653 }
09654 }
09655
09656 return 0;
09657 }
09658
09659
09660
09661
09662
09663
09664 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
09665 int priority, const char *label, const char *callerid,
09666 const char *application, void *data, void (*datad)(void *), const char *registrar)
09667 {
09668 int ret = -1;
09669 struct ast_context *c;
09670
09671 c = find_context(context);
09672 if (c) {
09673 ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
09674 application, data, datad, registrar, 1);
09675 }
09676
09677 return ret;
09678 }
09679
09680
09681
09682
09683
09684 int ast_add_extension(const char *context, int replace, const char *extension,
09685 int priority, const char *label, const char *callerid,
09686 const char *application, void *data, void (*datad)(void *), const char *registrar)
09687 {
09688 int ret = -1;
09689 struct ast_context *c;
09690
09691 c = find_context_locked(context);
09692 if (c) {
09693 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
09694 application, data, datad, registrar);
09695 ast_unlock_contexts();
09696 }
09697
09698 return ret;
09699 }
09700
09701 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
09702 {
09703 if (!chan)
09704 return -1;
09705
09706 ast_channel_lock(chan);
09707
09708 if (!ast_strlen_zero(context))
09709 ast_channel_context_set(chan, context);
09710 if (!ast_strlen_zero(exten))
09711 ast_channel_exten_set(chan, exten);
09712 if (priority > -1) {
09713
09714 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
09715 --priority;
09716 }
09717 ast_channel_priority_set(chan, priority);
09718 }
09719
09720 ast_channel_unlock(chan);
09721
09722 return 0;
09723 }
09724
09725 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
09726 {
09727 int res = 0;
09728 struct ast_channel *tmpchan;
09729 struct {
09730 char *accountcode;
09731 char *exten;
09732 char *context;
09733 char *linkedid;
09734 char *name;
09735 struct ast_cdr *cdr;
09736 int amaflags;
09737 int state;
09738 struct ast_format readformat;
09739 struct ast_format writeformat;
09740 } tmpvars = { 0, };
09741
09742 ast_channel_lock(chan);
09743 if (ast_channel_pbx(chan)) {
09744 ast_explicit_goto(chan, context, exten, priority + 1);
09745 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
09746 ast_channel_unlock(chan);
09747 return res;
09748 }
09749
09750
09751
09752
09753 tmpvars.accountcode = ast_strdupa(ast_channel_accountcode(chan));
09754 tmpvars.exten = ast_strdupa(ast_channel_exten(chan));
09755 tmpvars.context = ast_strdupa(ast_channel_context(chan));
09756 tmpvars.linkedid = ast_strdupa(ast_channel_linkedid(chan));
09757 tmpvars.name = ast_strdupa(ast_channel_name(chan));
09758 tmpvars.amaflags = ast_channel_amaflags(chan);
09759 tmpvars.state = ast_channel_state(chan);
09760 ast_format_copy(&tmpvars.writeformat, ast_channel_writeformat(chan));
09761 ast_format_copy(&tmpvars.readformat, ast_channel_readformat(chan));
09762 tmpvars.cdr = ast_channel_cdr(chan) ? ast_cdr_dup(ast_channel_cdr(chan)) : NULL;
09763
09764 ast_channel_unlock(chan);
09765
09766
09767
09768 if (!(tmpchan = ast_channel_alloc(0, tmpvars.state, 0, 0, tmpvars.accountcode, tmpvars.exten, tmpvars.context, tmpvars.linkedid, tmpvars.amaflags, "AsyncGoto/%s", tmpvars.name))) {
09769 ast_cdr_discard(tmpvars.cdr);
09770 return -1;
09771 }
09772
09773
09774 if (tmpvars.cdr) {
09775 ast_cdr_discard(ast_channel_cdr(tmpchan));
09776 ast_channel_cdr_set(tmpchan, tmpvars.cdr);
09777 tmpvars.cdr = NULL;
09778 }
09779
09780
09781 ast_format_copy(ast_channel_readformat(tmpchan), &tmpvars.readformat);
09782 ast_format_copy(ast_channel_writeformat(tmpchan), &tmpvars.writeformat);
09783
09784
09785 ast_explicit_goto(tmpchan, S_OR(context, tmpvars.context), S_OR(exten, tmpvars.exten), priority);
09786
09787
09788 if (ast_channel_masquerade(tmpchan, chan)) {
09789
09790
09791 ast_hangup(tmpchan);
09792 tmpchan = NULL;
09793 res = -1;
09794 } else {
09795 ast_do_masquerade(tmpchan);
09796
09797 if (ast_pbx_start(tmpchan)) {
09798 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmpchan));
09799 ast_hangup(tmpchan);
09800 res = -1;
09801 }
09802 }
09803
09804 return res;
09805 }
09806
09807 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
09808 {
09809 struct ast_channel *chan;
09810 int res = -1;
09811
09812 if ((chan = ast_channel_get_by_name(channame))) {
09813 res = ast_async_goto(chan, context, exten, priority);
09814 chan = ast_channel_unref(chan);
09815 }
09816
09817 return res;
09818 }
09819
09820
09821 static int ext_strncpy(char *dst, const char *src, int len)
09822 {
09823 int count = 0;
09824 int insquares = 0;
09825
09826 while (*src && (count < len - 1)) {
09827 if (*src == '[') {
09828 insquares = 1;
09829 } else if (*src == ']') {
09830 insquares = 0;
09831 } else if (*src == ' ' && !insquares) {
09832 src++;
09833 continue;
09834 }
09835 *dst = *src;
09836 dst++;
09837 src++;
09838 count++;
09839 }
09840 *dst = '\0';
09841
09842 return count;
09843 }
09844
09845
09846
09847
09848
09849
09850 static int add_priority(struct ast_context *con, struct ast_exten *tmp,
09851 struct ast_exten *el, struct ast_exten *e, int replace)
09852 {
09853 struct ast_exten *ep;
09854 struct ast_exten *eh=e;
09855 int repeated_label = 0;
09856
09857 for (ep = NULL; e ; ep = e, e = e->peer) {
09858 if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
09859 if (strcmp(e->exten, tmp->exten)) {
09860 ast_log(LOG_WARNING,
09861 "Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
09862 tmp->exten, tmp->priority, con->name, tmp->label, e->exten, e->priority);
09863 } else {
09864 ast_log(LOG_WARNING,
09865 "Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
09866 tmp->exten, tmp->priority, con->name, tmp->label, e->priority);
09867 }
09868 repeated_label = 1;
09869 }
09870 if (e->priority >= tmp->priority) {
09871 break;
09872 }
09873 }
09874
09875 if (repeated_label) {
09876 tmp->label = NULL;
09877 }
09878
09879 if (!e) {
09880 ast_hashtab_insert_safe(eh->peer_table, tmp);
09881
09882 if (tmp->label) {
09883 ast_hashtab_insert_safe(eh->peer_label_table, tmp);
09884 }
09885 ep->peer = tmp;
09886 return 0;
09887 }
09888 if (e->priority == tmp->priority) {
09889
09890
09891 if (!replace) {
09892 if (strcmp(e->exten, tmp->exten)) {
09893 ast_log(LOG_WARNING,
09894 "Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
09895 tmp->exten, tmp->priority, con->name, e->exten);
09896 } else {
09897 ast_log(LOG_WARNING,
09898 "Unable to register extension '%s' priority %d in '%s', already in use\n",
09899 tmp->exten, tmp->priority, con->name);
09900 }
09901 if (tmp->datad) {
09902 tmp->datad(tmp->data);
09903
09904 tmp->data = NULL;
09905 }
09906
09907 ast_free(tmp);
09908 return -1;
09909 }
09910
09911
09912
09913 tmp->next = e->next;
09914 tmp->peer = e->peer;
09915 if (ep) {
09916 ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
09917
09918 if (e->label) {
09919 ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
09920 }
09921
09922 ast_hashtab_insert_safe(eh->peer_table,tmp);
09923 if (tmp->label) {
09924 ast_hashtab_insert_safe(eh->peer_label_table,tmp);
09925 }
09926
09927 ep->peer = tmp;
09928 } else if (el) {
09929 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
09930 tmp->peer_table = e->peer_table;
09931 tmp->peer_label_table = e->peer_label_table;
09932 ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
09933 ast_hashtab_insert_safe(tmp->peer_table,tmp);
09934 if (e->label) {
09935 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
09936 }
09937 if (tmp->label) {
09938 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
09939 }
09940
09941 ast_hashtab_remove_object_via_lookup(con->root_table, e);
09942 ast_hashtab_insert_safe(con->root_table, tmp);
09943 el->next = tmp;
09944
09945
09946 if (x) {
09947 if (x->exten) {
09948 x->exten = tmp;
09949 } else {
09950 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
09951 }
09952 }
09953 } else {
09954 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
09955 ast_hashtab_remove_object_via_lookup(con->root_table, e);
09956 ast_hashtab_insert_safe(con->root_table, tmp);
09957 tmp->peer_table = e->peer_table;
09958 tmp->peer_label_table = e->peer_label_table;
09959 ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
09960 ast_hashtab_insert_safe(tmp->peer_table, tmp);
09961 if (e->label) {
09962 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
09963 }
09964 if (tmp->label) {
09965 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
09966 }
09967
09968 ast_hashtab_remove_object_via_lookup(con->root_table, e);
09969 ast_hashtab_insert_safe(con->root_table, tmp);
09970 con->root = tmp;
09971
09972
09973 if (x) {
09974 if (x->exten) {
09975 x->exten = tmp;
09976 } else {
09977 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
09978 }
09979 }
09980 }
09981 if (tmp->priority == PRIORITY_HINT)
09982 ast_change_hint(e,tmp);
09983
09984 if (e->datad)
09985 e->datad(e->data);
09986 ast_free(e);
09987 } else {
09988 tmp->peer = e;
09989 tmp->next = e->next;
09990 if (ep) {
09991 if (tmp->label) {
09992 ast_hashtab_insert_safe(eh->peer_label_table, tmp);
09993 }
09994 ast_hashtab_insert_safe(eh->peer_table, tmp);
09995 ep->peer = tmp;
09996 } else {
09997 tmp->peer_table = e->peer_table;
09998 tmp->peer_label_table = e->peer_label_table;
09999 e->peer_table = 0;
10000 e->peer_label_table = 0;
10001 ast_hashtab_insert_safe(tmp->peer_table, tmp);
10002 if (tmp->label) {
10003 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
10004 }
10005 ast_hashtab_remove_object_via_lookup(con->root_table, e);
10006 ast_hashtab_insert_safe(con->root_table, tmp);
10007 if (el)
10008 el->next = tmp;
10009 else
10010 con->root = tmp;
10011 e->next = NULL;
10012 }
10013
10014 if (tmp->priority == PRIORITY_HINT) {
10015 ast_add_hint(tmp);
10016 }
10017 }
10018 return 0;
10019 }
10020
10021
10022
10023
10024
10025
10026
10027
10028
10029
10030
10031
10032
10033
10034
10035
10036
10037
10038
10039
10040
10041
10042
10043
10044
10045
10046 int ast_add_extension2(struct ast_context *con,
10047 int replace, const char *extension, int priority, const char *label, const char *callerid,
10048 const char *application, void *data, void (*datad)(void *),
10049 const char *registrar)
10050 {
10051 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
10052 application, data, datad, registrar, 1);
10053 }
10054
10055
10056
10057
10058
10059
10060
10061
10062 static int ast_add_extension2_lockopt(struct ast_context *con,
10063 int replace, const char *extension, int priority, const char *label, const char *callerid,
10064 const char *application, void *data, void (*datad)(void *),
10065 const char *registrar, int lock_context)
10066 {
10067
10068
10069
10070
10071
10072
10073 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
10074 int res;
10075 int length;
10076 char *p;
10077 char expand_buf[VAR_BUF_SIZE];
10078 struct ast_exten dummy_exten = {0};
10079 char dummy_name[1024];
10080
10081 if (ast_strlen_zero(extension)) {
10082 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",
10083 con->name);
10084 return -1;
10085 }
10086
10087
10088 if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
10089 struct ast_channel *c = ast_dummy_channel_alloc();
10090
10091 if (c) {
10092 ast_channel_exten_set(c, extension);
10093 ast_channel_context_set(c, con->name);
10094 }
10095 pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
10096 application = expand_buf;
10097 if (c) {
10098 ast_channel_unref(c);
10099 }
10100 }
10101
10102 length = sizeof(struct ast_exten);
10103 length += strlen(extension) + 1;
10104 length += strlen(application) + 1;
10105 if (label)
10106 length += strlen(label) + 1;
10107 if (callerid)
10108 length += strlen(callerid) + 1;
10109 else
10110 length ++;
10111
10112
10113 if (!(tmp = ast_calloc(1, length)))
10114 return -1;
10115
10116 if (ast_strlen_zero(label))
10117 label = 0;
10118
10119
10120 p = tmp->stuff;
10121 if (label) {
10122 tmp->label = p;
10123 strcpy(p, label);
10124 p += strlen(label) + 1;
10125 }
10126 tmp->exten = p;
10127 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
10128 tmp->priority = priority;
10129 tmp->cidmatch = p;
10130
10131
10132 if (callerid) {
10133 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
10134 tmp->matchcid = AST_EXT_MATCHCID_ON;
10135 } else {
10136 *p++ = '\0';
10137 tmp->matchcid = AST_EXT_MATCHCID_OFF;
10138 }
10139 tmp->app = p;
10140 strcpy(p, application);
10141 tmp->parent = con;
10142 tmp->data = data;
10143 tmp->datad = datad;
10144 tmp->registrar = registrar;
10145
10146 if (lock_context) {
10147 ast_wrlock_context(con);
10148 }
10149
10150 if (con->pattern_tree) {
10151
10152 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
10153 dummy_exten.exten = dummy_name;
10154 dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
10155 dummy_exten.cidmatch = 0;
10156 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
10157 if (!tmp2) {
10158
10159 add_exten_to_pattern_tree(con, tmp, 0);
10160 ast_hashtab_insert_safe(con->root_table, tmp);
10161 }
10162 }
10163 res = 0;
10164 for (e = con->root; e; el = e, e = e->next) {
10165 res = ext_cmp(e->exten, tmp->exten);
10166 if (res == 0) {
10167 if (e->matchcid == AST_EXT_MATCHCID_OFF && tmp->matchcid == AST_EXT_MATCHCID_OFF)
10168 res = 0;
10169 else if (tmp->matchcid == AST_EXT_MATCHCID_ON && e->matchcid == AST_EXT_MATCHCID_OFF)
10170 res = 1;
10171 else if (e->matchcid == AST_EXT_MATCHCID_ON && tmp->matchcid == AST_EXT_MATCHCID_OFF)
10172 res = -1;
10173 else
10174 res = ext_cmp(e->cidmatch, tmp->cidmatch);
10175 }
10176 if (res >= 0)
10177 break;
10178 }
10179 if (e && res == 0) {
10180 res = add_priority(con, tmp, el, e, replace);
10181 if (lock_context) {
10182 ast_unlock_context(con);
10183 }
10184 if (res < 0) {
10185 errno = EEXIST;
10186 return 0;
10187 }
10188 } else {
10189
10190
10191
10192
10193 tmp->next = e;
10194 if (el) {
10195 el->next = tmp;
10196 tmp->peer_table = ast_hashtab_create(13,
10197 hashtab_compare_exten_numbers,
10198 ast_hashtab_resize_java,
10199 ast_hashtab_newsize_java,
10200 hashtab_hash_priority,
10201 0);
10202 tmp->peer_label_table = ast_hashtab_create(7,
10203 hashtab_compare_exten_labels,
10204 ast_hashtab_resize_java,
10205 ast_hashtab_newsize_java,
10206 hashtab_hash_labels,
10207 0);
10208 if (label) {
10209 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
10210 }
10211 ast_hashtab_insert_safe(tmp->peer_table, tmp);
10212 } else {
10213 if (!con->root_table)
10214 con->root_table = ast_hashtab_create(27,
10215 hashtab_compare_extens,
10216 ast_hashtab_resize_java,
10217 ast_hashtab_newsize_java,
10218 hashtab_hash_extens,
10219 0);
10220 con->root = tmp;
10221 con->root->peer_table = ast_hashtab_create(13,
10222 hashtab_compare_exten_numbers,
10223 ast_hashtab_resize_java,
10224 ast_hashtab_newsize_java,
10225 hashtab_hash_priority,
10226 0);
10227 con->root->peer_label_table = ast_hashtab_create(7,
10228 hashtab_compare_exten_labels,
10229 ast_hashtab_resize_java,
10230 ast_hashtab_newsize_java,
10231 hashtab_hash_labels,
10232 0);
10233 if (label) {
10234 ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
10235 }
10236 ast_hashtab_insert_safe(con->root->peer_table, tmp);
10237
10238 }
10239 ast_hashtab_insert_safe(con->root_table, tmp);
10240 if (lock_context) {
10241 ast_unlock_context(con);
10242 }
10243 if (tmp->priority == PRIORITY_HINT) {
10244 ast_add_hint(tmp);
10245 }
10246 }
10247 if (option_debug) {
10248 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
10249 ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
10250 tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
10251 } else {
10252 ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
10253 tmp->exten, tmp->priority, con->name, con);
10254 }
10255 }
10256
10257 if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
10258 ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
10259 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
10260 } else {
10261 ast_verb(3, "Added extension '%s' priority %d to %s\n",
10262 tmp->exten, tmp->priority, con->name);
10263 }
10264
10265 return 0;
10266 }
10267
10268 struct async_stat {
10269 pthread_t p;
10270 struct ast_channel *chan;
10271 char context[AST_MAX_CONTEXT];
10272 char exten[AST_MAX_EXTENSION];
10273 int priority;
10274 int timeout;
10275 char app[AST_MAX_EXTENSION];
10276 char appdata[1024];
10277 int early_media;
10278 };
10279
10280 static void *async_wait(void *data)
10281 {
10282 struct async_stat *as = data;
10283 struct ast_channel *chan = as->chan;
10284 int timeout = as->timeout;
10285 int res;
10286 struct ast_frame *f;
10287 struct ast_app *app;
10288 int have_early_media = 0;
10289 struct timeval start = ast_tvnow();
10290 int ms;
10291
10292 if (chan) {
10293 struct ast_callid *callid = ast_channel_callid(chan);
10294 if (callid) {
10295 ast_callid_threadassoc_add(callid);
10296 ast_callid_unref(callid);
10297 }
10298 }
10299
10300 while ((ms = ast_remaining_ms(start, timeout)) &&
10301 ast_channel_state(chan) != AST_STATE_UP) {
10302 res = ast_waitfor(chan, ms);
10303 if (res < 1)
10304 break;
10305
10306 f = ast_read(chan);
10307 if (!f)
10308 break;
10309 if (f->frametype == AST_FRAME_CONTROL) {
10310 if ((f->subclass.integer == AST_CONTROL_BUSY) ||
10311 (f->subclass.integer == AST_CONTROL_CONGESTION) ) {
10312 ast_frfree(f);
10313 break;
10314 }
10315 if (as->early_media && f->subclass.integer == AST_CONTROL_PROGRESS) {
10316 have_early_media = 1;
10317 ast_frfree(f);
10318 break;
10319 }
10320 }
10321 ast_frfree(f);
10322 }
10323 if (ast_channel_state(chan) == AST_STATE_UP || have_early_media) {
10324 if (have_early_media) {
10325 ast_debug(2, "Activating pbx since we have early media \n");
10326 }
10327 if (!ast_strlen_zero(as->app)) {
10328 app = pbx_findapp(as->app);
10329 if (app) {
10330 ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, ast_channel_name(chan));
10331 pbx_exec(chan, app, as->appdata);
10332 } else
10333 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
10334 } else {
10335 if (!ast_strlen_zero(as->context))
10336 ast_channel_context_set(chan, as->context);
10337 if (!ast_strlen_zero(as->exten))
10338 ast_channel_exten_set(chan, as->exten);
10339 if (as->priority > 0)
10340 ast_channel_priority_set(chan, as->priority);
10341
10342 if (ast_pbx_run(chan)) {
10343 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(chan));
10344 } else {
10345
10346 chan = NULL;
10347 }
10348 }
10349 }
10350 ast_free(as);
10351 if (chan)
10352 ast_hangup(chan);
10353 return NULL;
10354 }
10355
10356
10357
10358
10359
10360 static int ast_pbx_outgoing_cdr_failed(void)
10361 {
10362
10363 struct ast_channel *chan = ast_dummy_channel_alloc();
10364
10365 if (!chan)
10366 return -1;
10367
10368 ast_channel_cdr_set(chan, ast_cdr_alloc());
10369 if (!ast_channel_cdr(chan)) {
10370
10371 chan = ast_channel_unref(chan);
10372 return -1;
10373 }
10374
10375
10376 ast_cdr_init(ast_channel_cdr(chan), chan);
10377 ast_cdr_start(ast_channel_cdr(chan));
10378 ast_cdr_end(ast_channel_cdr(chan));
10379 ast_cdr_failed(ast_channel_cdr(chan));
10380 ast_cdr_detach(ast_channel_cdr(chan));
10381 ast_channel_cdr_set(chan, NULL);
10382 chan = ast_channel_unref(chan);
10383
10384 return 0;
10385 }
10386
10387 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)
10388 {
10389 struct ast_channel *chan;
10390 struct async_stat *as;
10391 struct ast_callid *callid;
10392 int callid_created = 0;
10393 int res = -1, cdr_res = -1;
10394 struct outgoing_helper oh;
10395
10396 oh.connect_on_early_media = early_media;
10397
10398 callid_created = ast_callid_threadstorage_auto(&callid);
10399
10400 if (synchronous) {
10401 oh.context = context;
10402 oh.exten = exten;
10403 oh.priority = priority;
10404 oh.cid_num = cid_num;
10405 oh.cid_name = cid_name;
10406 oh.account = account;
10407 oh.vars = vars;
10408 oh.parent_channel = NULL;
10409
10410 chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
10411 if (channel) {
10412 *channel = chan;
10413 if (chan)
10414 ast_channel_lock(chan);
10415 }
10416 if (chan) {
10417
10418 struct ast_callid *channel_callid = ast_channel_callid(chan);
10419 if (channel_callid) {
10420 ast_callid_unref(channel_callid);
10421 } else {
10422 if (callid) {
10423 ast_channel_callid_set(chan, callid);
10424 }
10425 }
10426
10427 if (ast_channel_state(chan) == AST_STATE_UP || (early_media && *reason == AST_CONTROL_PROGRESS)) {
10428 res = 0;
10429 ast_verb(4, "Channel %s %s\n", ast_channel_name(chan), ast_channel_state(chan) == AST_STATE_UP ? "was answered" : "got early media");
10430
10431 if (synchronous > 1) {
10432 if (channel)
10433 ast_channel_unlock(chan);
10434 if (ast_pbx_run(chan)) {
10435 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", ast_channel_name(chan));
10436 if (channel)
10437 *channel = NULL;
10438 ast_hangup(chan);
10439 chan = NULL;
10440 res = -1;
10441 }
10442 } else {
10443 if (ast_pbx_start(chan)) {
10444 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", ast_channel_name(chan));
10445 if (channel) {
10446 *channel = NULL;
10447 ast_channel_unlock(chan);
10448 }
10449 ast_hangup(chan);
10450 res = -1;
10451 }
10452 chan = NULL;
10453 }
10454 } else {
10455 ast_verb(4, "Channel %s was never answered.\n", ast_channel_name(chan));
10456
10457 if (ast_channel_cdr(chan)) {
10458
10459
10460 if (ast_cdr_disposition(ast_channel_cdr(chan), ast_channel_hangupcause(chan)))
10461 ast_cdr_failed(ast_channel_cdr(chan));
10462 }
10463
10464 if (channel) {
10465 *channel = NULL;
10466 ast_channel_unlock(chan);
10467 }
10468 ast_hangup(chan);
10469 chan = NULL;
10470 }
10471 }
10472
10473 if (res < 0) {
10474 if (*reason == 0) {
10475
10476 cdr_res = ast_pbx_outgoing_cdr_failed();
10477 if (cdr_res != 0) {
10478 res = cdr_res;
10479 goto outgoing_exten_cleanup;
10480 }
10481 }
10482
10483
10484
10485 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
10486 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", NULL, 0, "OutgoingSpoolFailed");
10487 if (chan) {
10488 char failed_reason[4] = "";
10489 if (!ast_strlen_zero(context))
10490 ast_channel_context_set(chan, context);
10491 set_ext_pri(chan, "failed", 1);
10492 ast_set_variables(chan, vars);
10493 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
10494 pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
10495 if (account)
10496 ast_cdr_setaccount(chan, account);
10497 if (ast_pbx_run(chan)) {
10498 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", ast_channel_name(chan));
10499 ast_hangup(chan);
10500 }
10501 chan = NULL;
10502 }
10503 }
10504 }
10505 } else {
10506 struct ast_callid *channel_callid;
10507 if (!(as = ast_calloc(1, sizeof(*as)))) {
10508 res = -1;
10509 goto outgoing_exten_cleanup;
10510 }
10511 chan = ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name);
10512 if (channel) {
10513 *channel = chan;
10514 if (chan)
10515 ast_channel_lock(chan);
10516 }
10517 if (!chan) {
10518 ast_free(as);
10519 res = -1;
10520 goto outgoing_exten_cleanup;
10521 }
10522
10523
10524 channel_callid = ast_channel_callid(chan);
10525 if (channel_callid) {
10526 ast_callid_unref(channel_callid);
10527 } else {
10528 if (callid) {
10529 ast_channel_callid_set(chan, callid);
10530 }
10531 }
10532
10533 as->chan = chan;
10534 ast_copy_string(as->context, context, sizeof(as->context));
10535 set_ext_pri(as->chan, exten, priority);
10536 as->timeout = timeout;
10537 ast_set_variables(chan, vars);
10538 if (account)
10539 ast_cdr_setaccount(chan, account);
10540 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
10541 ast_log(LOG_WARNING, "Failed to start async wait\n");
10542 ast_free(as);
10543 if (channel) {
10544 *channel = NULL;
10545 ast_channel_unlock(chan);
10546 }
10547 ast_hangup(chan);
10548 res = -1;
10549 goto outgoing_exten_cleanup;
10550 }
10551 res = 0;
10552 }
10553
10554 outgoing_exten_cleanup:
10555 ast_callid_threadstorage_auto_clean(callid, callid_created);
10556 ast_variables_destroy(vars);
10557 return res;
10558 }
10559
10560 struct app_tmp {
10561 struct ast_channel *chan;
10562 pthread_t t;
10563 AST_DECLARE_STRING_FIELDS (
10564 AST_STRING_FIELD(app);
10565 AST_STRING_FIELD(data);
10566 );
10567 };
10568
10569
10570 static void *ast_pbx_run_app(void *data)
10571 {
10572 struct app_tmp *tmp = data;
10573 struct ast_app *app;
10574 app = pbx_findapp(tmp->app);
10575 if (app) {
10576 ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, ast_channel_name(tmp->chan));
10577 pbx_exec(tmp->chan, app, tmp->data);
10578 } else
10579 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
10580 ast_hangup(tmp->chan);
10581 ast_string_field_free_memory(tmp);
10582 ast_free(tmp);
10583 return NULL;
10584 }
10585
10586 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)
10587 {
10588 struct ast_channel *chan;
10589 struct app_tmp *tmp;
10590 struct ast_callid *callid;
10591 int callid_created;
10592 int res = -1, cdr_res = -1;
10593 struct outgoing_helper oh;
10594
10595
10596 callid_created = ast_callid_threadstorage_auto(&callid);
10597
10598 memset(&oh, 0, sizeof(oh));
10599 oh.vars = vars;
10600 oh.account = account;
10601
10602 if (locked_channel)
10603 *locked_channel = NULL;
10604 if (ast_strlen_zero(app)) {
10605 res = -1;
10606 goto outgoing_app_cleanup;
10607 }
10608 if (synchronous) {
10609 chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
10610 if (chan) {
10611
10612 struct ast_callid *channel_callid = ast_channel_callid(chan);
10613 if (channel_callid) {
10614 ast_callid_unref(channel_callid);
10615 } else {
10616 if (callid) {
10617 ast_channel_callid_set(chan, callid);
10618 }
10619 }
10620
10621 ast_set_variables(chan, vars);
10622 if (account)
10623 ast_cdr_setaccount(chan, account);
10624 if (ast_channel_state(chan) == AST_STATE_UP) {
10625 res = 0;
10626 ast_verb(4, "Channel %s was answered.\n", ast_channel_name(chan));
10627 tmp = ast_calloc(1, sizeof(*tmp));
10628 if (!tmp || ast_string_field_init(tmp, 252)) {
10629 if (tmp) {
10630 ast_free(tmp);
10631 }
10632 res = -1;
10633 } else {
10634 ast_string_field_set(tmp, app, app);
10635 ast_string_field_set(tmp, data, appdata);
10636 tmp->chan = chan;
10637 if (synchronous > 1) {
10638 if (locked_channel)
10639 ast_channel_unlock(chan);
10640 ast_pbx_run_app(tmp);
10641 } else {
10642 if (locked_channel)
10643 ast_channel_lock(chan);
10644 if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
10645 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", ast_channel_name(chan), strerror(errno));
10646 ast_string_field_free_memory(tmp);
10647 ast_free(tmp);
10648 if (locked_channel)
10649 ast_channel_unlock(chan);
10650 ast_hangup(chan);
10651 res = -1;
10652 } else {
10653 if (locked_channel)
10654 *locked_channel = chan;
10655 }
10656 }
10657 }
10658 } else {
10659 ast_verb(4, "Channel %s was never answered.\n", ast_channel_name(chan));
10660 if (ast_channel_cdr(chan)) {
10661
10662
10663 if (ast_cdr_disposition(ast_channel_cdr(chan), ast_channel_hangupcause(chan)))
10664 ast_cdr_failed(ast_channel_cdr(chan));
10665 }
10666 ast_hangup(chan);
10667 }
10668 }
10669
10670 if (res < 0) {
10671 if (*reason == 0) {
10672
10673 cdr_res = ast_pbx_outgoing_cdr_failed();
10674 if (cdr_res != 0) {
10675 res = cdr_res;
10676 goto outgoing_app_cleanup;
10677 }
10678 }
10679 }
10680
10681 } else {
10682 struct async_stat *as;
10683 struct ast_callid *channel_callid;
10684 if (!(as = ast_calloc(1, sizeof(*as)))) {
10685 res = -1;
10686 goto outgoing_app_cleanup;
10687 }
10688 chan = __ast_request_and_dial(type, cap, NULL, addr, timeout, reason, cid_num, cid_name, &oh);
10689 if (!chan) {
10690 ast_free(as);
10691 res = -1;
10692 goto outgoing_app_cleanup;
10693 }
10694
10695
10696 channel_callid = ast_channel_callid(chan);
10697 if (channel_callid) {
10698 ast_callid_unref(channel_callid);
10699 } else {
10700 if (callid) {
10701 ast_channel_callid_set(chan, callid);
10702 }
10703 }
10704
10705 as->chan = chan;
10706 ast_copy_string(as->app, app, sizeof(as->app));
10707 if (appdata)
10708 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
10709 as->timeout = timeout;
10710 ast_set_variables(chan, vars);
10711 if (account)
10712 ast_cdr_setaccount(chan, account);
10713
10714 if (locked_channel)
10715 ast_channel_lock(chan);
10716 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
10717 ast_log(LOG_WARNING, "Failed to start async wait\n");
10718 ast_free(as);
10719 if (locked_channel)
10720 ast_channel_unlock(chan);
10721 ast_hangup(chan);
10722 res = -1;
10723 goto outgoing_app_cleanup;
10724 } else {
10725 if (locked_channel)
10726 *locked_channel = chan;
10727 }
10728 res = 0;
10729 }
10730
10731 outgoing_app_cleanup:
10732 ast_callid_threadstorage_auto_clean(callid, callid_created);
10733 ast_variables_destroy(vars);
10734 return res;
10735 }
10736
10737
10738
10739
10740
10741 static void __ast_internal_context_destroy( struct ast_context *con)
10742 {
10743 struct ast_include *tmpi;
10744 struct ast_sw *sw;
10745 struct ast_exten *e, *el, *en;
10746 struct ast_ignorepat *ipi;
10747 struct ast_context *tmp = con;
10748
10749 for (tmpi = tmp->includes; tmpi; ) {
10750 struct ast_include *tmpil = tmpi;
10751 tmpi = tmpi->next;
10752 ast_free(tmpil);
10753 }
10754 for (ipi = tmp->ignorepats; ipi; ) {
10755 struct ast_ignorepat *ipl = ipi;
10756 ipi = ipi->next;
10757 ast_free(ipl);
10758 }
10759 if (tmp->registrar)
10760 ast_free(tmp->registrar);
10761
10762
10763 if (tmp->root_table) {
10764 ast_hashtab_destroy(tmp->root_table, 0);
10765 }
10766
10767 if (tmp->pattern_tree)
10768 destroy_pattern_tree(tmp->pattern_tree);
10769
10770 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
10771 ast_free(sw);
10772 for (e = tmp->root; e;) {
10773 for (en = e->peer; en;) {
10774 el = en;
10775 en = en->peer;
10776 destroy_exten(el);
10777 }
10778 el = e;
10779 e = e->next;
10780 destroy_exten(el);
10781 }
10782 tmp->root = NULL;
10783 ast_rwlock_destroy(&tmp->lock);
10784 ast_mutex_destroy(&tmp->macrolock);
10785 ast_free(tmp);
10786 }
10787
10788
10789 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
10790 {
10791 struct ast_context *tmp, *tmpl=NULL;
10792 struct ast_exten *exten_item, *prio_item;
10793
10794 for (tmp = list; tmp; ) {
10795 struct ast_context *next = NULL;
10796
10797
10798
10799
10800 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
10801 if (con) {
10802 for (; tmp; tmpl = tmp, tmp = tmp->next) {
10803 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
10804 if ( !strcasecmp(tmp->name, con->name) ) {
10805 break;
10806 }
10807 }
10808 }
10809
10810 if (!tmp)
10811 break;
10812 ast_wrlock_context(tmp);
10813
10814 if (registrar) {
10815
10816 struct ast_hashtab_iter *exten_iter;
10817 struct ast_hashtab_iter *prio_iter;
10818 struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
10819 struct ast_include *i, *pi = NULL, *ni = NULL;
10820 struct ast_sw *sw = NULL;
10821
10822
10823 for (ip = tmp->ignorepats; ip; ip = ipn) {
10824 ipn = ip->next;
10825 if (!strcmp(ip->registrar, registrar)) {
10826 if (ipl) {
10827 ipl->next = ip->next;
10828 ast_free(ip);
10829 continue;
10830 } else {
10831 tmp->ignorepats = ip->next;
10832 ast_free(ip);
10833 continue;
10834 }
10835 }
10836 ipl = ip;
10837 }
10838
10839 for (i = tmp->includes; i; i = ni) {
10840 ni = i->next;
10841 if (strcmp(i->registrar, registrar) == 0) {
10842
10843 if (pi) {
10844 pi->next = i->next;
10845
10846 ast_free(i);
10847 continue;
10848 } else {
10849 tmp->includes = i->next;
10850
10851 ast_free(i);
10852 continue;
10853 }
10854 }
10855 pi = i;
10856 }
10857
10858 AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
10859 if (strcmp(sw->registrar,registrar) == 0) {
10860 AST_LIST_REMOVE_CURRENT(list);
10861 ast_free(sw);
10862 }
10863 }
10864 AST_LIST_TRAVERSE_SAFE_END;
10865
10866 if (tmp->root_table) {
10867 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
10868 while ((exten_item=ast_hashtab_next(exten_iter))) {
10869 int end_traversal = 1;
10870 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
10871 while ((prio_item=ast_hashtab_next(prio_iter))) {
10872 char extension[AST_MAX_EXTENSION];
10873 char cidmatch[AST_MAX_EXTENSION];
10874 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
10875 continue;
10876 }
10877 ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
10878 tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
10879 ast_copy_string(extension, prio_item->exten, sizeof(extension));
10880 if (prio_item->cidmatch) {
10881 ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
10882 }
10883 end_traversal &= ast_context_remove_extension_callerid2(tmp, extension, prio_item->priority, cidmatch, prio_item->matchcid, NULL, 1);
10884 }
10885
10886
10887
10888
10889
10890
10891
10892
10893 if (end_traversal) {
10894 ast_hashtab_end_traversal(prio_iter);
10895 } else {
10896 ast_free(prio_iter);
10897 }
10898 }
10899 ast_hashtab_end_traversal(exten_iter);
10900 }
10901
10902
10903
10904
10905 if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
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 } else {
10919 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
10920 tmp->refcount, tmp->root);
10921 ast_unlock_context(tmp);
10922 next = tmp->next;
10923 tmpl = tmp;
10924 }
10925 } else if (con) {
10926 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
10927 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
10928 ast_hashtab_remove_this_object(contexttab, tmp);
10929
10930 next = tmp->next;
10931 if (tmpl)
10932 tmpl->next = next;
10933 else
10934 contexts = next;
10935
10936
10937 ast_unlock_context(tmp);
10938 __ast_internal_context_destroy(tmp);
10939 }
10940
10941
10942 tmp = con ? NULL : next;
10943 }
10944 }
10945
10946 void ast_context_destroy(struct ast_context *con, const char *registrar)
10947 {
10948 ast_wrlock_contexts();
10949 __ast_context_destroy(contexts, contexts_table, con,registrar);
10950 ast_unlock_contexts();
10951 }
10952
10953 static void wait_for_hangup(struct ast_channel *chan, const void *data)
10954 {
10955 int res;
10956 struct ast_frame *f;
10957 double waitsec;
10958 int waittime;
10959
10960 if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
10961 waitsec = -1;
10962 if (waitsec > -1) {
10963 waittime = waitsec * 1000.0;
10964 ast_safe_sleep(chan, waittime);
10965 } else do {
10966 res = ast_waitfor(chan, -1);
10967 if (res < 0)
10968 return;
10969 f = ast_read(chan);
10970 if (f)
10971 ast_frfree(f);
10972 } while(f);
10973 }
10974
10975
10976
10977
10978 static int pbx_builtin_proceeding(struct ast_channel *chan, const char *data)
10979 {
10980 ast_indicate(chan, AST_CONTROL_PROCEEDING);
10981 return 0;
10982 }
10983
10984
10985
10986
10987 static int pbx_builtin_progress(struct ast_channel *chan, const char *data)
10988 {
10989 ast_indicate(chan, AST_CONTROL_PROGRESS);
10990 return 0;
10991 }
10992
10993
10994
10995
10996 static int pbx_builtin_ringing(struct ast_channel *chan, const char *data)
10997 {
10998 ast_indicate(chan, AST_CONTROL_RINGING);
10999 return 0;
11000 }
11001
11002
11003
11004
11005 static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
11006 {
11007 ast_indicate(chan, AST_CONTROL_BUSY);
11008
11009
11010 if (ast_channel_state(chan) != AST_STATE_UP) {
11011 ast_setstate(chan, AST_STATE_BUSY);
11012 ast_cdr_busy(ast_channel_cdr(chan));
11013 }
11014 wait_for_hangup(chan, data);
11015 return -1;
11016 }
11017
11018
11019
11020
11021 static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
11022 {
11023 ast_indicate(chan, AST_CONTROL_CONGESTION);
11024
11025
11026 if (ast_channel_state(chan) != AST_STATE_UP) {
11027 ast_setstate(chan, AST_STATE_BUSY);
11028 ast_cdr_congestion(ast_channel_cdr(chan));
11029 }
11030 wait_for_hangup(chan, data);
11031 return -1;
11032 }
11033
11034
11035
11036
11037 static int pbx_builtin_answer(struct ast_channel *chan, const char *data)
11038 {
11039 int delay = 0;
11040 int answer_cdr = 1;
11041 char *parse;
11042 AST_DECLARE_APP_ARGS(args,
11043 AST_APP_ARG(delay);
11044 AST_APP_ARG(answer_cdr);
11045 );
11046
11047 if (ast_strlen_zero(data)) {
11048 return __ast_answer(chan, 0, 1);
11049 }
11050
11051 parse = ast_strdupa(data);
11052
11053 AST_STANDARD_APP_ARGS(args, parse);
11054
11055 if (!ast_strlen_zero(args.delay) && (ast_channel_state(chan) != AST_STATE_UP))
11056 delay = atoi(data);
11057
11058 if (delay < 0) {
11059 delay = 0;
11060 }
11061
11062 if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
11063 answer_cdr = 0;
11064 }
11065
11066 return __ast_answer(chan, delay, answer_cdr);
11067 }
11068
11069 static int pbx_builtin_incomplete(struct ast_channel *chan, const char *data)
11070 {
11071 const char *options = data;
11072 int answer = 1;
11073
11074
11075 if (!ast_strlen_zero(options) && strchr(options, 'n')) {
11076 answer = 0;
11077 }
11078
11079
11080 if (ast_check_hangup(chan)) {
11081 return -1;
11082 } else if (ast_channel_state(chan) != AST_STATE_UP && answer) {
11083 __ast_answer(chan, 0, 1);
11084 }
11085
11086 ast_indicate(chan, AST_CONTROL_INCOMPLETE);
11087
11088 return AST_PBX_INCOMPLETE;
11089 }
11090
11091 AST_APP_OPTIONS(resetcdr_opts, {
11092 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
11093 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
11094 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
11095 AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),
11096 });
11097
11098
11099
11100
11101 static int pbx_builtin_resetcdr(struct ast_channel *chan, const char *data)
11102 {
11103 char *args;
11104 struct ast_flags flags = { 0 };
11105
11106 if (!ast_strlen_zero(data)) {
11107 args = ast_strdupa(data);
11108 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
11109 }
11110
11111 ast_cdr_reset(ast_channel_cdr(chan), &flags);
11112
11113 return 0;
11114 }
11115
11116
11117
11118
11119 static int pbx_builtin_setamaflags(struct ast_channel *chan, const char *data)
11120 {
11121
11122 ast_channel_lock(chan);
11123 ast_cdr_setamaflags(chan, data ? data : "");
11124 ast_channel_unlock(chan);
11125 return 0;
11126 }
11127
11128
11129
11130
11131 static int pbx_builtin_hangup(struct ast_channel *chan, const char *data)
11132 {
11133 int cause;
11134
11135 ast_set_hangupsource(chan, "dialplan/builtin", 0);
11136
11137 if (!ast_strlen_zero(data)) {
11138 cause = ast_str2cause(data);
11139 if (cause <= 0) {
11140 if (sscanf(data, "%30d", &cause) != 1 || cause <= 0) {
11141 ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", data);
11142 cause = 0;
11143 }
11144 }
11145 } else {
11146 cause = 0;
11147 }
11148
11149 ast_channel_lock(chan);
11150 if (cause <= 0) {
11151 cause = ast_channel_hangupcause(chan);
11152 if (cause <= 0) {
11153 cause = AST_CAUSE_NORMAL_CLEARING;
11154 }
11155 }
11156 ast_channel_hangupcause_set(chan, cause);
11157 ast_softhangup_nolock(chan, AST_SOFTHANGUP_EXPLICIT);
11158 ast_channel_unlock(chan);
11159
11160 return -1;
11161 }
11162
11163
11164
11165
11166 static int testtime_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
11167 {
11168 struct ast_tm tm;
11169 struct timeval tv;
11170 char *remainder, result[30], timezone[80];
11171
11172
11173 if (!pbx_checkcondition(value)) {
11174 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
11175 return 0;
11176 }
11177
11178
11179 if (!(remainder = ast_strptime(value, "%Y/%m/%d %H:%M:%S", &tm))) {
11180 return -1;
11181 }
11182 sscanf(remainder, "%79s", timezone);
11183 tv = ast_mktime(&tm, S_OR(timezone, NULL));
11184
11185 snprintf(result, sizeof(result), "%ld", (long) tv.tv_sec);
11186 pbx_builtin_setvar_helper(chan, "__TESTTIME", result);
11187 return 0;
11188 }
11189
11190 static struct ast_custom_function testtime_function = {
11191 .name = "TESTTIME",
11192 .write = testtime_write,
11193 };
11194
11195
11196
11197
11198 static int pbx_builtin_gotoiftime(struct ast_channel *chan, const char *data)
11199 {
11200 char *s, *ts, *branch1, *branch2, *branch;
11201 struct ast_timing timing;
11202 const char *ctime;
11203 struct timeval tv = ast_tvnow();
11204 long timesecs;
11205
11206 if (!chan) {
11207 ast_log(LOG_WARNING, "GotoIfTime requires a channel on which to operate\n");
11208 return -1;
11209 }
11210
11211 if (ast_strlen_zero(data)) {
11212 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
11213 return -1;
11214 }
11215
11216 ts = s = ast_strdupa(data);
11217
11218 ast_channel_lock(chan);
11219 if ((ctime = pbx_builtin_getvar_helper(chan, "TESTTIME")) && sscanf(ctime, "%ld", ×ecs) == 1) {
11220 tv.tv_sec = timesecs;
11221 } else if (ctime) {
11222 ast_log(LOG_WARNING, "Using current time to evaluate\n");
11223
11224 pbx_builtin_setvar_helper(chan, "TESTTIME", NULL);
11225 }
11226 ast_channel_unlock(chan);
11227
11228
11229 strsep(&ts, "?");
11230 branch1 = strsep(&ts,":");
11231 branch2 = strsep(&ts,"");
11232
11233
11234 if (ast_build_timing(&timing, s) && ast_check_timing2(&timing, tv)) {
11235 branch = branch1;
11236 } else {
11237 branch = branch2;
11238 }
11239 ast_destroy_timing(&timing);
11240
11241 if (ast_strlen_zero(branch)) {
11242 ast_debug(1, "Not taking any branch\n");
11243 return 0;
11244 }
11245
11246 return pbx_builtin_goto(chan, branch);
11247 }
11248
11249
11250
11251
11252 static int pbx_builtin_execiftime(struct ast_channel *chan, const char *data)
11253 {
11254 char *s, *appname;
11255 struct ast_timing timing;
11256 struct ast_app *app;
11257 static const char * const usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
11258
11259 if (ast_strlen_zero(data)) {
11260 ast_log(LOG_WARNING, "%s\n", usage);
11261 return -1;
11262 }
11263
11264 appname = ast_strdupa(data);
11265
11266 s = strsep(&appname, "?");
11267 if (!appname) {
11268 ast_log(LOG_WARNING, "%s\n", usage);
11269 return -1;
11270 }
11271
11272 if (!ast_build_timing(&timing, s)) {
11273 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
11274 ast_destroy_timing(&timing);
11275 return -1;
11276 }
11277
11278 if (!ast_check_timing(&timing)) {
11279 ast_destroy_timing(&timing);
11280 return 0;
11281 }
11282 ast_destroy_timing(&timing);
11283
11284
11285 if ((s = strchr(appname, '('))) {
11286 char *e;
11287 *s++ = '\0';
11288 if ((e = strrchr(s, ')')))
11289 *e = '\0';
11290 else
11291 ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
11292 }
11293
11294
11295 if ((app = pbx_findapp(appname))) {
11296 return pbx_exec(chan, app, S_OR(s, ""));
11297 } else {
11298 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
11299 return -1;
11300 }
11301 }
11302
11303
11304
11305
11306 static int pbx_builtin_wait(struct ast_channel *chan, const char *data)
11307 {
11308 int ms;
11309
11310
11311 if (!ast_app_parse_timelen(data, &ms, TIMELEN_SECONDS) && ms > 0) {
11312 return ast_safe_sleep(chan, ms);
11313 }
11314 return 0;
11315 }
11316
11317
11318
11319
11320 static int pbx_builtin_waitexten(struct ast_channel *chan, const char *data)
11321 {
11322 int ms, res;
11323 struct ast_flags flags = {0};
11324 char *opts[1] = { NULL };
11325 char *parse;
11326 AST_DECLARE_APP_ARGS(args,
11327 AST_APP_ARG(timeout);
11328 AST_APP_ARG(options);
11329 );
11330
11331 if (!ast_strlen_zero(data)) {
11332 parse = ast_strdupa(data);
11333 AST_STANDARD_APP_ARGS(args, parse);
11334 } else
11335 memset(&args, 0, sizeof(args));
11336
11337 if (args.options)
11338 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
11339
11340 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
11341 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
11342 } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
11343 ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL),
11344 !ast_strlen_zero(opts[0]) ? strlen(opts[0]) + 1 : 0);
11345 } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
11346 struct ast_tone_zone_sound *ts = ast_get_indication_tone(ast_channel_zone(chan), "dial");
11347 if (ts) {
11348 ast_playtones_start(chan, 0, ts->data, 0);
11349 ts = ast_tone_zone_sound_unref(ts);
11350 } else {
11351 ast_tonepair_start(chan, 350, 440, 0, 0);
11352 }
11353 }
11354
11355 if (!ast_app_parse_timelen(args.timeout, &ms, TIMELEN_SECONDS) && ms > 0) {
11356
11357 } else if (ast_channel_pbx(chan)) {
11358 ms = ast_channel_pbx(chan)->rtimeoutms;
11359 } else {
11360 ms = 10000;
11361 }
11362
11363 res = ast_waitfordigit(chan, ms);
11364 if (!res) {
11365 if (ast_check_hangup(chan)) {
11366
11367 res = -1;
11368 } else if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1,
11369 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
11370 ast_verb(3, "Timeout on %s, continuing...\n", ast_channel_name(chan));
11371 } else if (ast_exists_extension(chan, ast_channel_context(chan), "t", 1,
11372 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
11373 ast_verb(3, "Timeout on %s, going to 't'\n", ast_channel_name(chan));
11374 set_ext_pri(chan, "t", 0);
11375 } else if (ast_exists_extension(chan, ast_channel_context(chan), "e", 1,
11376 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
11377 raise_exception(chan, "RESPONSETIMEOUT", 0);
11378 } else {
11379 ast_log(LOG_WARNING, "Timeout but no rule 't' or 'e' in context '%s'\n",
11380 ast_channel_context(chan));
11381 res = -1;
11382 }
11383 }
11384
11385 if (ast_test_flag(&flags, WAITEXTEN_MOH))
11386 ast_indicate(chan, AST_CONTROL_UNHOLD);
11387 else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
11388 ast_playtones_stop(chan);
11389
11390 return res;
11391 }
11392
11393
11394
11395
11396 static int pbx_builtin_background(struct ast_channel *chan, const char *data)
11397 {
11398 int res = 0;
11399 int mres = 0;
11400 struct ast_flags flags = {0};
11401 char *parse, exten[2] = "";
11402 AST_DECLARE_APP_ARGS(args,
11403 AST_APP_ARG(filename);
11404 AST_APP_ARG(options);
11405 AST_APP_ARG(lang);
11406 AST_APP_ARG(context);
11407 );
11408
11409 if (ast_strlen_zero(data)) {
11410 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
11411 return -1;
11412 }
11413
11414 parse = ast_strdupa(data);
11415
11416 AST_STANDARD_APP_ARGS(args, parse);
11417
11418 if (ast_strlen_zero(args.lang))
11419 args.lang = (char *)ast_channel_language(chan);
11420
11421 if (ast_strlen_zero(args.context)) {
11422 const char *context;
11423 ast_channel_lock(chan);
11424 if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
11425 args.context = ast_strdupa(context);
11426 } else {
11427 args.context = ast_strdupa(ast_channel_context(chan));
11428 }
11429 ast_channel_unlock(chan);
11430 }
11431
11432 if (args.options) {
11433 if (!strcasecmp(args.options, "skip"))
11434 flags.flags = BACKGROUND_SKIP;
11435 else if (!strcasecmp(args.options, "noanswer"))
11436 flags.flags = BACKGROUND_NOANSWER;
11437 else
11438 ast_app_parse_options(background_opts, &flags, NULL, args.options);
11439 }
11440
11441
11442 if (ast_channel_state(chan) != AST_STATE_UP) {
11443 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
11444 goto done;
11445 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
11446 res = ast_answer(chan);
11447 }
11448 }
11449
11450 if (!res) {
11451 char *back = ast_strip(args.filename);
11452 char *front;
11453
11454 ast_stopstream(chan);
11455
11456 while (!res && (front = strsep(&back, "&")) ) {
11457 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
11458 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", ast_channel_name(chan), (char*)data);
11459 res = 0;
11460 mres = 1;
11461 break;
11462 }
11463 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
11464 res = ast_waitstream(chan, "");
11465 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
11466 res = ast_waitstream_exten(chan, args.context);
11467 } else {
11468 res = ast_waitstream(chan, AST_DIGIT_ANY);
11469 }
11470 ast_stopstream(chan);
11471 }
11472 }
11473
11474
11475
11476
11477
11478
11479
11480
11481
11482
11483
11484
11485
11486
11487
11488
11489
11490
11491
11492 if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_WORKAROUNDS)
11493 && (exten[0] = res)
11494 && ast_canmatch_extension(chan, args.context, exten, 1,
11495 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))
11496 && !ast_matchmore_extension(chan, args.context, exten, 1,
11497 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
11498 char buf[2] = { 0, };
11499 snprintf(buf, sizeof(buf), "%c", res);
11500 ast_channel_exten_set(chan, buf);
11501 ast_channel_context_set(chan, args.context);
11502 ast_channel_priority_set(chan, 0);
11503 res = 0;
11504 }
11505 done:
11506 pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
11507 return res;
11508 }
11509
11510
11511
11512
11513 static int pbx_builtin_goto(struct ast_channel *chan, const char *data)
11514 {
11515 int res = ast_parseable_goto(chan, data);
11516 if (!res)
11517 ast_verb(3, "Goto (%s,%s,%d)\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan) + 1);
11518 return res;
11519 }
11520
11521
11522 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
11523 {
11524 struct ast_var_t *variables;
11525 const char *var, *val;
11526 int total = 0;
11527
11528 if (!chan)
11529 return 0;
11530
11531 ast_str_reset(*buf);
11532
11533 ast_channel_lock(chan);
11534
11535 AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
11536 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
11537
11538 ) {
11539 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
11540 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
11541 break;
11542 } else
11543 total++;
11544 } else
11545 break;
11546 }
11547
11548 ast_channel_unlock(chan);
11549
11550 return total;
11551 }
11552
11553 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
11554 {
11555 struct ast_var_t *variables;
11556 const char *ret = NULL;
11557 int i;
11558 struct varshead *places[2] = { NULL, &globals };
11559
11560 if (!name)
11561 return NULL;
11562
11563 if (chan) {
11564 ast_channel_lock(chan);
11565 places[0] = ast_channel_varshead(chan);
11566 }
11567
11568 for (i = 0; i < 2; i++) {
11569 if (!places[i])
11570 continue;
11571 if (places[i] == &globals)
11572 ast_rwlock_rdlock(&globalslock);
11573 AST_LIST_TRAVERSE(places[i], variables, entries) {
11574 if (!strcmp(name, ast_var_name(variables))) {
11575 ret = ast_var_value(variables);
11576 break;
11577 }
11578 }
11579 if (places[i] == &globals)
11580 ast_rwlock_unlock(&globalslock);
11581 if (ret)
11582 break;
11583 }
11584
11585 if (chan)
11586 ast_channel_unlock(chan);
11587
11588 return ret;
11589 }
11590
11591 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
11592 {
11593 struct ast_var_t *newvariable;
11594 struct varshead *headp;
11595
11596 if (name[strlen(name)-1] == ')') {
11597 char *function = ast_strdupa(name);
11598
11599 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
11600 ast_func_write(chan, function, value);
11601 return;
11602 }
11603
11604 if (chan) {
11605 ast_channel_lock(chan);
11606 headp = ast_channel_varshead(chan);
11607 } else {
11608 ast_rwlock_wrlock(&globalslock);
11609 headp = &globals;
11610 }
11611
11612 if (value && (newvariable = ast_var_assign(name, value))) {
11613 if (headp == &globals)
11614 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
11615 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
11616 }
11617
11618 if (chan)
11619 ast_channel_unlock(chan);
11620 else
11621 ast_rwlock_unlock(&globalslock);
11622 }
11623
11624 int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
11625 {
11626 struct ast_var_t *newvariable;
11627 struct varshead *headp;
11628 const char *nametail = name;
11629
11630 if (name[strlen(name) - 1] == ')') {
11631 char *function = ast_strdupa(name);
11632
11633 return ast_func_write(chan, function, value);
11634 }
11635
11636 if (chan) {
11637 ast_channel_lock(chan);
11638 headp = ast_channel_varshead(chan);
11639 } else {
11640 ast_rwlock_wrlock(&globalslock);
11641 headp = &globals;
11642 }
11643
11644
11645 if (*nametail == '_') {
11646 nametail++;
11647 if (*nametail == '_')
11648 nametail++;
11649 }
11650
11651 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
11652 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
11653
11654 AST_LIST_REMOVE_CURRENT(entries);
11655 ast_var_delete(newvariable);
11656 break;
11657 }
11658 }
11659 AST_LIST_TRAVERSE_SAFE_END;
11660
11661 if (value && (newvariable = ast_var_assign(name, value))) {
11662 if (headp == &globals)
11663 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
11664 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
11665
11666
11667
11668
11669
11670 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
11671 "Channel: %s\r\n"
11672 "Variable: %s\r\n"
11673 "Value: %s\r\n"
11674 "Uniqueid: %s\r\n",
11675 chan ? ast_channel_name(chan) : "none", name, value,
11676 chan ? ast_channel_uniqueid(chan) : "none");
11677 }
11678
11679 if (chan)
11680 ast_channel_unlock(chan);
11681 else
11682 ast_rwlock_unlock(&globalslock);
11683 return 0;
11684 }
11685
11686 int pbx_builtin_setvar(struct ast_channel *chan, const char *data)
11687 {
11688 char *name, *value, *mydata;
11689
11690 if (ast_compat_app_set) {
11691 return pbx_builtin_setvar_multiple(chan, data);
11692 }
11693
11694 if (ast_strlen_zero(data)) {
11695 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
11696 return 0;
11697 }
11698
11699 mydata = ast_strdupa(data);
11700 name = strsep(&mydata, "=");
11701 value = mydata;
11702 if (!value) {
11703 ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
11704 return 0;
11705 }
11706
11707 if (strchr(name, ' ')) {
11708 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
11709 }
11710
11711 pbx_builtin_setvar_helper(chan, name, value);
11712
11713 return 0;
11714 }
11715
11716 int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *vdata)
11717 {
11718 char *data;
11719 int x;
11720 AST_DECLARE_APP_ARGS(args,
11721 AST_APP_ARG(pair)[24];
11722 );
11723 AST_DECLARE_APP_ARGS(pair,
11724 AST_APP_ARG(name);
11725 AST_APP_ARG(value);
11726 );
11727
11728 if (ast_strlen_zero(vdata)) {
11729 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
11730 return 0;
11731 }
11732
11733 data = ast_strdupa(vdata);
11734 AST_STANDARD_APP_ARGS(args, data);
11735
11736 for (x = 0; x < args.argc; x++) {
11737 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
11738 if (pair.argc == 2) {
11739 pbx_builtin_setvar_helper(chan, pair.name, pair.value);
11740 if (strchr(pair.name, ' '))
11741 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);
11742 } else if (!chan) {
11743 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
11744 } else {
11745 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));
11746 }
11747 }
11748
11749 return 0;
11750 }
11751
11752 int pbx_builtin_importvar(struct ast_channel *chan, const char *data)
11753 {
11754 char *name;
11755 char *value;
11756 char *channel;
11757 char tmp[VAR_BUF_SIZE];
11758 static int deprecation_warning = 0;
11759
11760 if (ast_strlen_zero(data)) {
11761 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
11762 return 0;
11763 }
11764 tmp[0] = 0;
11765 if (!deprecation_warning) {
11766 ast_log(LOG_WARNING, "ImportVar is deprecated. Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
11767 deprecation_warning = 1;
11768 }
11769
11770 value = ast_strdupa(data);
11771 name = strsep(&value,"=");
11772 channel = strsep(&value,",");
11773 if (channel && value && name) {
11774 struct ast_channel *chan2 = ast_channel_get_by_name(channel);
11775 if (chan2) {
11776 char *s = ast_alloca(strlen(value) + 4);
11777 sprintf(s, "${%s}", value);
11778 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
11779 chan2 = ast_channel_unref(chan2);
11780 }
11781 pbx_builtin_setvar_helper(chan, name, tmp);
11782 }
11783
11784 return(0);
11785 }
11786
11787 static int pbx_builtin_noop(struct ast_channel *chan, const char *data)
11788 {
11789 return 0;
11790 }
11791
11792 void pbx_builtin_clear_globals(void)
11793 {
11794 struct ast_var_t *vardata;
11795
11796 ast_rwlock_wrlock(&globalslock);
11797 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
11798 ast_var_delete(vardata);
11799 ast_rwlock_unlock(&globalslock);
11800 }
11801
11802 int pbx_checkcondition(const char *condition)
11803 {
11804 int res;
11805 if (ast_strlen_zero(condition)) {
11806 return 0;
11807 } else if (sscanf(condition, "%30d", &res) == 1) {
11808 return res;
11809 } else {
11810 return 1;
11811 }
11812 }
11813
11814 static int pbx_builtin_gotoif(struct ast_channel *chan, const char *data)
11815 {
11816 char *condition, *branch1, *branch2, *branch;
11817 char *stringp;
11818
11819 if (ast_strlen_zero(data)) {
11820 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
11821 return 0;
11822 }
11823
11824 stringp = ast_strdupa(data);
11825 condition = strsep(&stringp,"?");
11826 branch1 = strsep(&stringp,":");
11827 branch2 = strsep(&stringp,"");
11828 branch = pbx_checkcondition(condition) ? branch1 : branch2;
11829
11830 if (ast_strlen_zero(branch)) {
11831 ast_debug(1, "Not taking any branch\n");
11832 return 0;
11833 }
11834
11835 return pbx_builtin_goto(chan, branch);
11836 }
11837
11838 static int pbx_builtin_saynumber(struct ast_channel *chan, const char *data)
11839 {
11840 char tmp[256];
11841 char *number = tmp;
11842 char *options;
11843
11844 if (ast_strlen_zero(data)) {
11845 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
11846 return -1;
11847 }
11848 ast_copy_string(tmp, data, sizeof(tmp));
11849 strsep(&number, ",");
11850 options = strsep(&number, ",");
11851 if (options) {
11852 if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
11853 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
11854 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
11855 return -1;
11856 }
11857 }
11858
11859 if (ast_say_number(chan, atoi(tmp), "", ast_channel_language(chan), options)) {
11860 ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
11861 }
11862
11863 return 0;
11864 }
11865
11866 static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data)
11867 {
11868 int res = 0;
11869
11870 if (data)
11871 res = ast_say_digit_str(chan, data, "", ast_channel_language(chan));
11872 return res;
11873 }
11874
11875 static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data)
11876 {
11877 int res = 0;
11878
11879 if (data)
11880 res = ast_say_character_str(chan, data, "", ast_channel_language(chan));
11881 return res;
11882 }
11883
11884 static int pbx_builtin_sayphonetic(struct ast_channel *chan, const char *data)
11885 {
11886 int res = 0;
11887
11888 if (data)
11889 res = ast_say_phonetic_str(chan, data, "", ast_channel_language(chan));
11890 return res;
11891 }
11892
11893 static void presencechange_destroy(void *data)
11894 {
11895 struct presencechange *pc = data;
11896 ast_free(pc->provider);
11897 ast_free(pc->subtype);
11898 ast_free(pc->message);
11899 }
11900
11901 static void presence_state_cb(const struct ast_event *event, void *unused)
11902 {
11903 struct presencechange *pc;
11904 const char *tmp;
11905
11906 if (!(pc = ao2_alloc(sizeof(*pc), presencechange_destroy))) {
11907 return;
11908 }
11909
11910 tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_PROVIDER);
11911 if (ast_strlen_zero(tmp)) {
11912 ast_log(LOG_ERROR, "Received invalid event that had no presence provider IE\n");
11913 ao2_ref(pc, -1);
11914 return;
11915 }
11916 pc->provider = ast_strdup(tmp);
11917
11918 pc->state = ast_event_get_ie_uint(event, AST_EVENT_IE_PRESENCE_STATE);
11919 if (pc->state < 0) {
11920 ao2_ref(pc, -1);
11921 return;
11922 }
11923
11924 if ((tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_SUBTYPE))) {
11925 pc->subtype = ast_strdup(tmp);
11926 }
11927
11928 if ((tmp = ast_event_get_ie_str(event, AST_EVENT_IE_PRESENCE_MESSAGE))) {
11929 pc->message = ast_strdup(tmp);
11930 }
11931
11932
11933 if (ast_taskprocessor_push(extension_state_tps, handle_presencechange, pc) < 0) {
11934 ao2_ref(pc, -1);
11935 }
11936 }
11937
11938 static void device_state_cb(const struct ast_event *event, void *unused)
11939 {
11940 const char *device;
11941 struct statechange *sc;
11942
11943 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
11944 if (ast_strlen_zero(device)) {
11945 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
11946 return;
11947 }
11948
11949 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
11950 return;
11951 strcpy(sc->dev, device);
11952 if (ast_taskprocessor_push(extension_state_tps, handle_statechange, sc) < 0) {
11953 ast_free(sc);
11954 }
11955 }
11956
11957
11958
11959
11960
11961 static int hints_data_provider_get(const struct ast_data_search *search,
11962 struct ast_data *data_root)
11963 {
11964 struct ast_data *data_hint;
11965 struct ast_hint *hint;
11966 int watchers;
11967 struct ao2_iterator i;
11968
11969 if (ao2_container_count(hints) == 0) {
11970 return 0;
11971 }
11972
11973 i = ao2_iterator_init(hints, 0);
11974 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
11975 watchers = ao2_container_count(hint->callbacks);
11976 data_hint = ast_data_add_node(data_root, "hint");
11977 if (!data_hint) {
11978 continue;
11979 }
11980 ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten));
11981 ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
11982 ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
11983 ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
11984 ast_data_add_str(data_hint, "presence_state", ast_presence_state2str(hint->last_presence_state));
11985 ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_subtype, ""));
11986 ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_message, ""));
11987 ast_data_add_int(data_hint, "watchers", watchers);
11988
11989 if (!ast_data_search_match(search, data_hint)) {
11990 ast_data_remove_node(data_root, data_hint);
11991 }
11992 }
11993 ao2_iterator_destroy(&i);
11994
11995 return 0;
11996 }
11997
11998 static const struct ast_data_handler hints_data_provider = {
11999 .version = AST_DATA_HANDLER_VERSION,
12000 .get = hints_data_provider_get
12001 };
12002
12003 static const struct ast_data_entry pbx_data_providers[] = {
12004 AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
12005 };
12006
12007
12008
12009 static void unload_pbx(void)
12010 {
12011 int x;
12012
12013 if (presence_state_sub) {
12014 presence_state_sub = ast_event_unsubscribe(presence_state_sub);
12015 }
12016 if (device_state_sub) {
12017 device_state_sub = ast_event_unsubscribe(device_state_sub);
12018 }
12019
12020
12021 for (x = 0; x < ARRAY_LEN(builtins); x++) {
12022 ast_unregister_application(builtins[x].name);
12023 }
12024 ast_manager_unregister("ShowDialPlan");
12025 ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
12026 ast_custom_function_unregister(&exception_function);
12027 ast_custom_function_unregister(&testtime_function);
12028 ast_data_unregister(NULL);
12029 if (extension_state_tps) {
12030 extension_state_tps = ast_taskprocessor_unreference(extension_state_tps);
12031 }
12032 }
12033
12034 int load_pbx(void)
12035 {
12036 int x;
12037
12038 ast_register_atexit(unload_pbx);
12039
12040
12041 ast_verb(1, "Asterisk PBX Core Initializing\n");
12042 if (!(extension_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
12043 ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
12044 }
12045
12046 ast_verb(1, "Registering builtin applications:\n");
12047 ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
12048 ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
12049 __ast_custom_function_register(&exception_function, NULL);
12050 __ast_custom_function_register(&testtime_function, NULL);
12051
12052
12053 for (x = 0; x < ARRAY_LEN(builtins); x++) {
12054 ast_verb(1, "[%s]\n", builtins[x].name);
12055 if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
12056 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
12057 return -1;
12058 }
12059 }
12060
12061
12062 ast_manager_register_xml_core("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan);
12063
12064 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "pbx Device State Change", NULL,
12065 AST_EVENT_IE_END))) {
12066 return -1;
12067 }
12068
12069 if (!(presence_state_sub = ast_event_subscribe(AST_EVENT_PRESENCE_STATE, presence_state_cb, "pbx Presence State Change", NULL,
12070 AST_EVENT_IE_END))) {
12071 return -1;
12072 }
12073
12074 return 0;
12075 }
12076
12077
12078
12079
12080 int ast_wrlock_contexts(void)
12081 {
12082 return ast_mutex_lock(&conlock);
12083 }
12084
12085 int ast_rdlock_contexts(void)
12086 {
12087 return ast_mutex_lock(&conlock);
12088 }
12089
12090 int ast_unlock_contexts(void)
12091 {
12092 return ast_mutex_unlock(&conlock);
12093 }
12094
12095
12096
12097
12098 int ast_wrlock_context(struct ast_context *con)
12099 {
12100 return ast_rwlock_wrlock(&con->lock);
12101 }
12102
12103 int ast_rdlock_context(struct ast_context *con)
12104 {
12105 return ast_rwlock_rdlock(&con->lock);
12106 }
12107
12108 int ast_unlock_context(struct ast_context *con)
12109 {
12110 return ast_rwlock_unlock(&con->lock);
12111 }
12112
12113
12114
12115
12116 const char *ast_get_context_name(struct ast_context *con)
12117 {
12118 return con ? con->name : NULL;
12119 }
12120
12121 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
12122 {
12123 return exten ? exten->parent : NULL;
12124 }
12125
12126 const char *ast_get_extension_name(struct ast_exten *exten)
12127 {
12128 return exten ? exten->exten : NULL;
12129 }
12130
12131 const char *ast_get_extension_label(struct ast_exten *exten)
12132 {
12133 return exten ? exten->label : NULL;
12134 }
12135
12136 const char *ast_get_include_name(struct ast_include *inc)
12137 {
12138 return inc ? inc->name : NULL;
12139 }
12140
12141 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
12142 {
12143 return ip ? ip->pattern : NULL;
12144 }
12145
12146 int ast_get_extension_priority(struct ast_exten *exten)
12147 {
12148 return exten ? exten->priority : -1;
12149 }
12150
12151
12152
12153
12154 const char *ast_get_context_registrar(struct ast_context *c)
12155 {
12156 return c ? c->registrar : NULL;
12157 }
12158
12159 const char *ast_get_extension_registrar(struct ast_exten *e)
12160 {
12161 return e ? e->registrar : NULL;
12162 }
12163
12164 const char *ast_get_include_registrar(struct ast_include *i)
12165 {
12166 return i ? i->registrar : NULL;
12167 }
12168
12169 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
12170 {
12171 return ip ? ip->registrar : NULL;
12172 }
12173
12174 int ast_get_extension_matchcid(struct ast_exten *e)
12175 {
12176 return e ? e->matchcid : 0;
12177 }
12178
12179 const char *ast_get_extension_cidmatch(struct ast_exten *e)
12180 {
12181 return e ? e->cidmatch : NULL;
12182 }
12183
12184 const char *ast_get_extension_app(struct ast_exten *e)
12185 {
12186 return e ? e->app : NULL;
12187 }
12188
12189 void *ast_get_extension_app_data(struct ast_exten *e)
12190 {
12191 return e ? e->data : NULL;
12192 }
12193
12194 const char *ast_get_switch_name(struct ast_sw *sw)
12195 {
12196 return sw ? sw->name : NULL;
12197 }
12198
12199 const char *ast_get_switch_data(struct ast_sw *sw)
12200 {
12201 return sw ? sw->data : NULL;
12202 }
12203
12204 int ast_get_switch_eval(struct ast_sw *sw)
12205 {
12206 return sw->eval;
12207 }
12208
12209 const char *ast_get_switch_registrar(struct ast_sw *sw)
12210 {
12211 return sw ? sw->registrar : NULL;
12212 }
12213
12214
12215
12216
12217 struct ast_context *ast_walk_contexts(struct ast_context *con)
12218 {
12219 return con ? con->next : contexts;
12220 }
12221
12222 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
12223 struct ast_exten *exten)
12224 {
12225 if (!exten)
12226 return con ? con->root : NULL;
12227 else
12228 return exten->next;
12229 }
12230
12231 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
12232 struct ast_sw *sw)
12233 {
12234 if (!sw)
12235 return con ? AST_LIST_FIRST(&con->alts) : NULL;
12236 else
12237 return AST_LIST_NEXT(sw, list);
12238 }
12239
12240 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
12241 struct ast_exten *priority)
12242 {
12243 return priority ? priority->peer : exten;
12244 }
12245
12246 struct ast_include *ast_walk_context_includes(struct ast_context *con,
12247 struct ast_include *inc)
12248 {
12249 if (!inc)
12250 return con ? con->includes : NULL;
12251 else
12252 return inc->next;
12253 }
12254
12255 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
12256 struct ast_ignorepat *ip)
12257 {
12258 if (!ip)
12259 return con ? con->ignorepats : NULL;
12260 else
12261 return ip->next;
12262 }
12263
12264 int ast_context_verify_includes(struct ast_context *con)
12265 {
12266 struct ast_include *inc = NULL;
12267 int res = 0;
12268
12269 while ( (inc = ast_walk_context_includes(con, inc)) ) {
12270 if (ast_context_find(inc->rname))
12271 continue;
12272
12273 res = -1;
12274 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
12275 ast_get_context_name(con), inc->rname);
12276 break;
12277 }
12278
12279 return res;
12280 }
12281
12282
12283 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
12284 {
12285 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
12286
12287 if (!chan)
12288 return -2;
12289
12290 if (context == NULL)
12291 context = ast_channel_context(chan);
12292 if (exten == NULL)
12293 exten = ast_channel_exten(chan);
12294
12295 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
12296 if (ast_exists_extension(chan, context, exten, priority,
12297 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL)))
12298 return goto_func(chan, context, exten, priority);
12299 else {
12300 return AST_PBX_GOTO_FAILED;
12301 }
12302 }
12303
12304 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
12305 {
12306 return __ast_goto_if_exists(chan, context, exten, priority, 0);
12307 }
12308
12309 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
12310 {
12311 return __ast_goto_if_exists(chan, context, exten, priority, 1);
12312 }
12313
12314 static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
12315 {
12316 char *exten, *pri, *context;
12317 char *stringp;
12318 int ipri;
12319 int mode = 0;
12320
12321 if (ast_strlen_zero(goto_string)) {
12322 ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
12323 return -1;
12324 }
12325 stringp = ast_strdupa(goto_string);
12326 context = strsep(&stringp, ",");
12327 exten = strsep(&stringp, ",");
12328 pri = strsep(&stringp, ",");
12329 if (!exten) {
12330 pri = context;
12331 exten = NULL;
12332 context = NULL;
12333 } else if (!pri) {
12334 pri = exten;
12335 exten = context;
12336 context = NULL;
12337 }
12338 if (*pri == '+') {
12339 mode = 1;
12340 pri++;
12341 } else if (*pri == '-') {
12342 mode = -1;
12343 pri++;
12344 }
12345 if (sscanf(pri, "%30d", &ipri) != 1) {
12346 ipri = ast_findlabel_extension(chan, context ? context : ast_channel_context(chan),
12347 exten ? exten : ast_channel_exten(chan), pri,
12348 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
12349 if (ipri < 1) {
12350 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
12351 return -1;
12352 } else
12353 mode = 0;
12354 }
12355
12356
12357 if (mode)
12358 ipri = ast_channel_priority(chan) + (ipri * mode);
12359
12360 if (async)
12361 ast_async_goto(chan, context, exten, ipri);
12362 else
12363 ast_explicit_goto(chan, context, exten, ipri);
12364
12365 return 0;
12366
12367 }
12368
12369 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
12370 {
12371 return pbx_parseable_goto(chan, goto_string, 0);
12372 }
12373
12374 int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
12375 {
12376 return pbx_parseable_goto(chan, goto_string, 1);
12377 }
12378
12379 char *ast_complete_applications(const char *line, const char *word, int state)
12380 {
12381 struct ast_app *app = NULL;
12382 int which = 0;
12383 char *ret = NULL;
12384 size_t wordlen = strlen(word);
12385
12386 AST_RWLIST_RDLOCK(&apps);
12387 AST_RWLIST_TRAVERSE(&apps, app, list) {
12388 if (!strncasecmp(word, app->name, wordlen) && ++which > state) {
12389 ret = ast_strdup(app->name);
12390 break;
12391 }
12392 }
12393 AST_RWLIST_UNLOCK(&apps);
12394
12395 return ret;
12396 }
12397
12398 static int hint_hash(const void *obj, const int flags)
12399 {
12400 const struct ast_hint *hint = obj;
12401 const char *exten_name;
12402 int res;
12403
12404 exten_name = ast_get_extension_name(hint->exten);
12405 if (ast_strlen_zero(exten_name)) {
12406
12407
12408
12409
12410 res = 0;
12411 } else {
12412 res = ast_str_case_hash(exten_name);
12413 }
12414
12415 return res;
12416 }
12417
12418 static int hint_cmp(void *obj, void *arg, int flags)
12419 {
12420 const struct ast_hint *hint = obj;
12421 const struct ast_exten *exten = arg;
12422
12423 return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
12424 }
12425
12426 static int statecbs_cmp(void *obj, void *arg, int flags)
12427 {
12428 const struct ast_state_cb *state_cb = obj;
12429 ast_state_cb_type change_cb = arg;
12430
12431 return (state_cb->change_cb == change_cb) ? CMP_MATCH | CMP_STOP : 0;
12432 }
12433
12434
12435
12436
12437
12438 static void pbx_shutdown(void)
12439 {
12440 if (hints) {
12441 ao2_ref(hints, -1);
12442 hints = NULL;
12443 }
12444 if (hintdevices) {
12445 ao2_ref(hintdevices, -1);
12446 hintdevices = NULL;
12447 }
12448 if (statecbs) {
12449 ao2_ref(statecbs, -1);
12450 statecbs = NULL;
12451 }
12452 if (contexts_table) {
12453 ast_hashtab_destroy(contexts_table, NULL);
12454 }
12455 pbx_builtin_clear_globals();
12456 }
12457
12458 int ast_pbx_init(void)
12459 {
12460 hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
12461 hintdevices = ao2_container_alloc(HASH_EXTENHINT_SIZE, hintdevice_hash_cb, hintdevice_cmp_multiple);
12462 statecbs = ao2_container_alloc(1, NULL, statecbs_cmp);
12463
12464 ast_register_atexit(pbx_shutdown);
12465
12466 return (hints && hintdevices && statecbs) ? 0 : -1;
12467 }