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: 374778 $")
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
00830
00831
00832 struct ast_exten {
00833 char *exten;
00834 int matchcid;
00835 const char *cidmatch;
00836 int priority;
00837 const char *label;
00838 struct ast_context *parent;
00839 const char *app;
00840 struct ast_app *cached_app;
00841 void *data;
00842 void (*datad)(void *);
00843 struct ast_exten *peer;
00844 struct ast_hashtab *peer_table;
00845 struct ast_hashtab *peer_label_table;
00846 const char *registrar;
00847 struct ast_exten *next;
00848 char stuff[0];
00849 };
00850
00851
00852 struct ast_include {
00853 const char *name;
00854 const char *rname;
00855 const char *registrar;
00856 int hastime;
00857 struct ast_timing timing;
00858 struct ast_include *next;
00859 char stuff[0];
00860 };
00861
00862
00863 struct ast_sw {
00864 char *name;
00865 const char *registrar;
00866 char *data;
00867 int eval;
00868 AST_LIST_ENTRY(ast_sw) list;
00869 char stuff[0];
00870 };
00871
00872
00873 struct ast_ignorepat {
00874 const char *registrar;
00875 struct ast_ignorepat *next;
00876 const char pattern[0];
00877 };
00878
00879
00880 struct match_char
00881 {
00882 int is_pattern;
00883 int deleted;
00884 int specificity;
00885 struct match_char *alt_char;
00886 struct match_char *next_char;
00887 struct ast_exten *exten;
00888 char x[1];
00889 };
00890
00891 struct scoreboard
00892 {
00893 int total_specificity;
00894 int total_length;
00895 char last_char;
00896 int canmatch;
00897 struct match_char *node;
00898 struct ast_exten *canmatch_exten;
00899 struct ast_exten *exten;
00900 };
00901
00902
00903 struct ast_context {
00904 ast_rwlock_t lock;
00905 struct ast_exten *root;
00906 struct ast_hashtab *root_table;
00907 struct match_char *pattern_tree;
00908 struct ast_context *next;
00909 struct ast_include *includes;
00910 struct ast_ignorepat *ignorepats;
00911 char *registrar;
00912 int refcount;
00913 AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
00914 ast_mutex_t macrolock;
00915 char name[0];
00916 };
00917
00918
00919 struct ast_app {
00920 int (*execute)(struct ast_channel *chan, const char *data);
00921 AST_DECLARE_STRING_FIELDS(
00922 AST_STRING_FIELD(synopsis);
00923 AST_STRING_FIELD(description);
00924 AST_STRING_FIELD(syntax);
00925 AST_STRING_FIELD(arguments);
00926 AST_STRING_FIELD(seealso);
00927 );
00928 #ifdef AST_XML_DOCS
00929 enum ast_doc_src docsrc;
00930 #endif
00931 AST_RWLIST_ENTRY(ast_app) list;
00932 struct ast_module *module;
00933 char name[0];
00934 };
00935
00936
00937 struct ast_state_cb {
00938
00939 int id;
00940
00941 void *data;
00942
00943 int extended;
00944
00945 ast_state_cb_type change_cb;
00946
00947 ast_state_cb_destroy_type destroy_cb;
00948
00949 AST_LIST_ENTRY(ast_state_cb) entry;
00950 };
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960 struct ast_hint {
00961
00962
00963
00964
00965
00966
00967 struct ast_exten *exten;
00968 struct ao2_container *callbacks;
00969
00970
00971 int laststate;
00972
00973
00974 int last_presence_state;
00975 char *last_presence_subtype;
00976 char *last_presence_message;
00977
00978 char context_name[AST_MAX_CONTEXT];
00979 char exten_name[AST_MAX_EXTENSION];
00980 };
00981
00982
00983 #define HINTDEVICE_DATA_LENGTH 16
00984 AST_THREADSTORAGE(hintdevice_data);
00985
00986
00987 #ifdef LOW_MEMORY
00988 #define HASH_EXTENHINT_SIZE 17
00989 #else
00990 #define HASH_EXTENHINT_SIZE 563
00991 #endif
00992
00993
00994
00995 static struct ao2_container *hintdevices;
00996
00997
00998
00999
01000
01001 struct ast_hintdevice {
01002
01003
01004
01005
01006 struct ast_hint *hint;
01007
01008 char hintdevice[1];
01009 };
01010
01011
01012
01013
01014
01015 static int hintdevice_hash_cb(const void *obj, const int flags)
01016 {
01017 const struct ast_hintdevice *ext = obj;
01018
01019 return ast_str_case_hash(ext->hintdevice);
01020 }
01021
01022
01023
01024
01025
01026 static int hintdevice_cmp_multiple(void *obj, void *arg, int flags)
01027 {
01028 struct ast_hintdevice *ext = obj, *ext2 = arg;
01029
01030 return !strcasecmp(ext->hintdevice, ext2->hintdevice) ? CMP_MATCH : 0;
01031 }
01032
01033
01034
01035
01036
01037 static int hintdevice_remove_cb(void *deviceobj, void *arg, int flags)
01038 {
01039 struct ast_hintdevice *device = deviceobj;
01040 struct ast_hint *hint = arg;
01041
01042 return (device->hint == hint) ? CMP_MATCH : 0;
01043 }
01044
01045 static int remove_hintdevice(struct ast_hint *hint)
01046 {
01047
01048 ao2_t_callback(hintdevices, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK,
01049 hintdevice_remove_cb, hint,
01050 "callback to remove all devices which are linked to a hint");
01051 return 0;
01052 }
01053
01054 static char *parse_hint_device(struct ast_str *hint_args);
01055
01056
01057
01058
01059
01060
01061
01062
01063 static void hintdevice_destroy(void *obj)
01064 {
01065 struct ast_hintdevice *doomed = obj;
01066
01067 if (doomed->hint) {
01068 ao2_ref(doomed->hint, -1);
01069 doomed->hint = NULL;
01070 }
01071 }
01072
01073
01074
01075 static int add_hintdevice(struct ast_hint *hint, const char *devicelist)
01076 {
01077 struct ast_str *str;
01078 char *parse;
01079 char *cur;
01080 struct ast_hintdevice *device;
01081 int devicelength;
01082
01083 if (!hint || !devicelist) {
01084
01085 return 0;
01086 }
01087 if (!(str = ast_str_thread_get(&hintdevice_data, 16))) {
01088 return -1;
01089 }
01090 ast_str_set(&str, 0, "%s", devicelist);
01091 parse = parse_hint_device(str);
01092
01093 while ((cur = strsep(&parse, "&"))) {
01094 devicelength = strlen(cur);
01095 device = ao2_t_alloc(sizeof(*device) + devicelength, hintdevice_destroy,
01096 "allocating a hintdevice structure");
01097 if (!device) {
01098 return -1;
01099 }
01100 strcpy(device->hintdevice, cur);
01101 ao2_ref(hint, +1);
01102 device->hint = hint;
01103 ao2_t_link(hintdevices, device, "Linking device into hintdevice container.");
01104 ao2_t_ref(device, -1, "hintdevice is linked so we can unref");
01105 }
01106
01107 return 0;
01108 }
01109
01110
01111 static const struct cfextension_states {
01112 int extension_state;
01113 const char * const text;
01114 } extension_states[] = {
01115 { AST_EXTENSION_NOT_INUSE, "Idle" },
01116 { AST_EXTENSION_INUSE, "InUse" },
01117 { AST_EXTENSION_BUSY, "Busy" },
01118 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
01119 { AST_EXTENSION_RINGING, "Ringing" },
01120 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
01121 { AST_EXTENSION_ONHOLD, "Hold" },
01122 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
01123 };
01124
01125 struct presencechange {
01126 char *provider;
01127 int state;
01128 char *subtype;
01129 char *message;
01130 };
01131
01132 struct statechange {
01133 AST_LIST_ENTRY(statechange) entry;
01134 char dev[0];
01135 };
01136
01137 struct pbx_exception {
01138 AST_DECLARE_STRING_FIELDS(
01139 AST_STRING_FIELD(context);
01140 AST_STRING_FIELD(exten);
01141 AST_STRING_FIELD(reason);
01142 );
01143
01144 int priority;
01145 };
01146
01147 static int pbx_builtin_answer(struct ast_channel *, const char *);
01148 static int pbx_builtin_goto(struct ast_channel *, const char *);
01149 static int pbx_builtin_hangup(struct ast_channel *, const char *);
01150 static int pbx_builtin_background(struct ast_channel *, const char *);
01151 static int pbx_builtin_wait(struct ast_channel *, const char *);
01152 static int pbx_builtin_waitexten(struct ast_channel *, const char *);
01153 static int pbx_builtin_incomplete(struct ast_channel *, const char *);
01154 static int pbx_builtin_resetcdr(struct ast_channel *, const char *);
01155 static int pbx_builtin_setamaflags(struct ast_channel *, const char *);
01156 static int pbx_builtin_ringing(struct ast_channel *, const char *);
01157 static int pbx_builtin_proceeding(struct ast_channel *, const char *);
01158 static int pbx_builtin_progress(struct ast_channel *, const char *);
01159 static int pbx_builtin_congestion(struct ast_channel *, const char *);
01160 static int pbx_builtin_busy(struct ast_channel *, const char *);
01161 static int pbx_builtin_noop(struct ast_channel *, const char *);
01162 static int pbx_builtin_gotoif(struct ast_channel *, const char *);
01163 static int pbx_builtin_gotoiftime(struct ast_channel *, const char *);
01164 static int pbx_builtin_execiftime(struct ast_channel *, const char *);
01165 static int pbx_builtin_saynumber(struct ast_channel *, const char *);
01166 static int pbx_builtin_saydigits(struct ast_channel *, const char *);
01167 static int pbx_builtin_saycharacters(struct ast_channel *, const char *);
01168 static int pbx_builtin_sayphonetic(struct ast_channel *, const char *);
01169 static int matchcid(const char *cidpattern, const char *callerid);
01170 #ifdef NEED_DEBUG
01171 static void log_match_char_tree(struct match_char *node, char *prefix);
01172 #endif
01173 static int pbx_builtin_importvar(struct ast_channel *, const char *);
01174 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
01175 static void new_find_extension(const char *str, struct scoreboard *score,
01176 struct match_char *tree, int length, int spec, const char *callerid,
01177 const char *label, enum ext_match_t action);
01178 static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
01179 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
01180 struct ast_exten *e1, int findonly);
01181 static void create_match_char_tree(struct ast_context *con);
01182 static struct ast_exten *get_canmatch_exten(struct match_char *node);
01183 static void destroy_pattern_tree(struct match_char *pattern_tree);
01184 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
01185 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
01186 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
01187 static unsigned int hashtab_hash_extens(const void *obj);
01188 static unsigned int hashtab_hash_priority(const void *obj);
01189 static unsigned int hashtab_hash_labels(const void *obj);
01190 static void __ast_internal_context_destroy( struct ast_context *con);
01191 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
01192 int priority, const char *label, const char *callerid,
01193 const char *application, void *data, void (*datad)(void *), const char *registrar);
01194 static int ast_add_extension2_lockopt(struct ast_context *con,
01195 int replace, const char *extension, int priority, const char *label, const char *callerid,
01196 const char *application, void *data, void (*datad)(void *),
01197 const char *registrar, int lock_context);
01198 static struct ast_context *find_context_locked(const char *context);
01199 static struct ast_context *find_context(const char *context);
01200 static void get_device_state_causing_channels(struct ao2_container *c);
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213 static int compare_char(const void *a, const void *b)
01214 {
01215 const unsigned char *ac = a;
01216 const unsigned char *bc = b;
01217
01218 return *ac - *bc;
01219 }
01220
01221
01222 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
01223 {
01224 const struct ast_context *ac = ah_a;
01225 const struct ast_context *bc = ah_b;
01226 if (!ac || !bc)
01227 return 1;
01228
01229 return strcmp(ac->name, bc->name);
01230 }
01231
01232 static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
01233 {
01234 const struct ast_exten *ac = ah_a;
01235 const struct ast_exten *bc = ah_b;
01236 int x = strcmp(ac->exten, bc->exten);
01237 if (x) {
01238 return x;
01239 }
01240
01241
01242 if (ac->matchcid && bc->matchcid) {
01243 return strcmp(ac->cidmatch,bc->cidmatch);
01244 } else if (!ac->matchcid && !bc->matchcid) {
01245 return 0;
01246 } else {
01247 return 1;
01248 }
01249 }
01250
01251 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
01252 {
01253 const struct ast_exten *ac = ah_a;
01254 const struct ast_exten *bc = ah_b;
01255 return ac->priority != bc->priority;
01256 }
01257
01258 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
01259 {
01260 const struct ast_exten *ac = ah_a;
01261 const struct ast_exten *bc = ah_b;
01262 return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
01263 }
01264
01265 unsigned int ast_hashtab_hash_contexts(const void *obj)
01266 {
01267 const struct ast_context *ac = obj;
01268 return ast_hashtab_hash_string(ac->name);
01269 }
01270
01271 static unsigned int hashtab_hash_extens(const void *obj)
01272 {
01273 const struct ast_exten *ac = obj;
01274 unsigned int x = ast_hashtab_hash_string(ac->exten);
01275 unsigned int y = 0;
01276 if (ac->matchcid)
01277 y = ast_hashtab_hash_string(ac->cidmatch);
01278 return x+y;
01279 }
01280
01281 static unsigned int hashtab_hash_priority(const void *obj)
01282 {
01283 const struct ast_exten *ac = obj;
01284 return ast_hashtab_hash_int(ac->priority);
01285 }
01286
01287 static unsigned int hashtab_hash_labels(const void *obj)
01288 {
01289 const struct ast_exten *ac = obj;
01290 return ast_hashtab_hash_string(S_OR(ac->label, ""));
01291 }
01292
01293
01294 AST_RWLOCK_DEFINE_STATIC(globalslock);
01295 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
01296
01297 static int autofallthrough = 1;
01298 static int extenpatternmatchnew = 0;
01299 static char *overrideswitch = NULL;
01300
01301
01302 static struct ast_event_sub *device_state_sub;
01303
01304 static struct ast_event_sub *presence_state_sub;
01305
01306 AST_MUTEX_DEFINE_STATIC(maxcalllock);
01307 static int countcalls;
01308 static int totalcalls;
01309
01310 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
01311
01312
01313 static struct pbx_builtin {
01314 char name[AST_MAX_APP];
01315 int (*execute)(struct ast_channel *chan, const char *data);
01316 } builtins[] =
01317 {
01318
01319
01320
01321 { "Answer", pbx_builtin_answer },
01322 { "BackGround", pbx_builtin_background },
01323 { "Busy", pbx_builtin_busy },
01324 { "Congestion", pbx_builtin_congestion },
01325 { "ExecIfTime", pbx_builtin_execiftime },
01326 { "Goto", pbx_builtin_goto },
01327 { "GotoIf", pbx_builtin_gotoif },
01328 { "GotoIfTime", pbx_builtin_gotoiftime },
01329 { "ImportVar", pbx_builtin_importvar },
01330 { "Hangup", pbx_builtin_hangup },
01331 { "Incomplete", pbx_builtin_incomplete },
01332 { "NoOp", pbx_builtin_noop },
01333 { "Proceeding", pbx_builtin_proceeding },
01334 { "Progress", pbx_builtin_progress },
01335 { "RaiseException", pbx_builtin_raise_exception },
01336 { "ResetCDR", pbx_builtin_resetcdr },
01337 { "Ringing", pbx_builtin_ringing },
01338 { "SayAlpha", pbx_builtin_saycharacters },
01339 { "SayDigits", pbx_builtin_saydigits },
01340 { "SayNumber", pbx_builtin_saynumber },
01341 { "SayPhonetic", pbx_builtin_sayphonetic },
01342 { "Set", pbx_builtin_setvar },
01343 { "MSet", pbx_builtin_setvar_multiple },
01344 { "SetAMAFlags", pbx_builtin_setamaflags },
01345 { "Wait", pbx_builtin_wait },
01346 { "WaitExten", pbx_builtin_waitexten }
01347 };
01348
01349 static struct ast_context *contexts;
01350 static struct ast_hashtab *contexts_table = NULL;
01351
01352
01353
01354
01355
01356
01357
01358 AST_MUTEX_DEFINE_STATIC(conlock);
01359
01360
01361
01362
01363 AST_MUTEX_DEFINE_STATIC(context_merge_lock);
01364
01365 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
01366
01367 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
01368
01369 static int stateid = 1;
01370
01371
01372
01373
01374
01375
01376
01377
01378 static struct ao2_container *hints;
01379
01380 static struct ao2_container *statecbs;
01381
01382 #ifdef CONTEXT_DEBUG
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396 void check_contexts_trouble(void);
01397
01398 void check_contexts_trouble(void)
01399 {
01400 int x = 1;
01401 x = 2;
01402 }
01403
01404 int check_contexts(char *, int);
01405
01406 int check_contexts(char *file, int line )
01407 {
01408 struct ast_hashtab_iter *t1;
01409 struct ast_context *c1, *c2;
01410 int found = 0;
01411 struct ast_exten *e1, *e2, *e3;
01412 struct ast_exten ex;
01413
01414
01415
01416
01417 if (!contexts_table) {
01418 ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
01419 usleep(500000);
01420 }
01421
01422 t1 = ast_hashtab_start_traversal(contexts_table);
01423 while( (c1 = ast_hashtab_next(t1))) {
01424 for(c2=contexts;c2;c2=c2->next) {
01425 if (!strcmp(c1->name, c2->name)) {
01426 found = 1;
01427 break;
01428 }
01429 }
01430 if (!found) {
01431 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
01432 check_contexts_trouble();
01433 }
01434 }
01435 ast_hashtab_end_traversal(t1);
01436 for(c2=contexts;c2;c2=c2->next) {
01437 c1 = find_context_locked(c2->name);
01438 if (!c1) {
01439 ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
01440 check_contexts_trouble();
01441 } else
01442 ast_unlock_contexts();
01443 }
01444
01445
01446
01447 for(c2=contexts;c2;c2=c2->next) {
01448 c1 = find_context_locked(c2->name);
01449 if (c1) {
01450 ast_unlock_contexts();
01451
01452
01453 for(e1 = c1->root; e1; e1=e1->next)
01454 {
01455 char dummy_name[1024];
01456 ex.exten = dummy_name;
01457 ex.matchcid = e1->matchcid;
01458 ex.cidmatch = e1->cidmatch;
01459 ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
01460 e2 = ast_hashtab_lookup(c1->root_table, &ex);
01461 if (!e2) {
01462 if (e1->matchcid) {
01463 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 );
01464 } else {
01465 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 );
01466 }
01467 check_contexts_trouble();
01468 }
01469 }
01470
01471
01472 if (!c2->root_table) {
01473 if (c2->root) {
01474 ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
01475 usleep(500000);
01476 }
01477 } else {
01478 t1 = ast_hashtab_start_traversal(c2->root_table);
01479 while( (e2 = ast_hashtab_next(t1)) ) {
01480 for(e1=c2->root;e1;e1=e1->next) {
01481 if (!strcmp(e1->exten, e2->exten)) {
01482 found = 1;
01483 break;
01484 }
01485 }
01486 if (!found) {
01487 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);
01488 check_contexts_trouble();
01489 }
01490
01491 }
01492 ast_hashtab_end_traversal(t1);
01493 }
01494 }
01495
01496
01497
01498
01499
01500 for(e1 = c2->root; e1; e1 = e1->next) {
01501
01502 for(e2=e1;e2;e2=e2->peer) {
01503 ex.priority = e2->priority;
01504 if (e2 != e1 && e2->peer_table) {
01505 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 );
01506 check_contexts_trouble();
01507 }
01508
01509 if (e2 != e1 && e2->peer_label_table) {
01510 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 );
01511 check_contexts_trouble();
01512 }
01513
01514 if (e2 == e1 && !e2->peer_table){
01515 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 );
01516 check_contexts_trouble();
01517 }
01518
01519 if (e2 == e1 && !e2->peer_label_table) {
01520 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 );
01521 check_contexts_trouble();
01522 }
01523
01524
01525 e3 = ast_hashtab_lookup(e1->peer_table, &ex);
01526 if (!e3) {
01527 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 );
01528 check_contexts_trouble();
01529 }
01530 }
01531
01532 if (!e1->peer_table){
01533 ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
01534 usleep(500000);
01535 }
01536
01537
01538 t1 = ast_hashtab_start_traversal(e1->peer_table);
01539 while( (e2 = ast_hashtab_next(t1)) ) {
01540 for(e3=e1;e3;e3=e3->peer) {
01541 if (e3->priority == e2->priority) {
01542 found = 1;
01543 break;
01544 }
01545 }
01546 if (!found) {
01547 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 );
01548 check_contexts_trouble();
01549 }
01550 }
01551 ast_hashtab_end_traversal(t1);
01552 }
01553 }
01554 return 0;
01555 }
01556 #endif
01557
01558
01559
01560
01561 int pbx_exec(struct ast_channel *c,
01562 struct ast_app *app,
01563 const char *data)
01564 {
01565 int res;
01566 struct ast_module_user *u = NULL;
01567 const char *saved_c_appl;
01568 const char *saved_c_data;
01569
01570 if (ast_channel_cdr(c) && !ast_check_hangup(c))
01571 ast_cdr_setapp(ast_channel_cdr(c), app->name, data);
01572
01573
01574 saved_c_appl= ast_channel_appl(c);
01575 saved_c_data= ast_channel_data(c);
01576
01577 ast_channel_appl_set(c, app->name);
01578 ast_channel_data_set(c, data);
01579 ast_cel_report_event(c, AST_CEL_APP_START, NULL, NULL, NULL);
01580
01581 if (app->module)
01582 u = __ast_module_user_add(app->module, c);
01583 if (strcasecmp(app->name, "system") && !ast_strlen_zero(data) &&
01584 strchr(data, '|') && !strchr(data, ',') && !ast_opt_dont_warn) {
01585 ast_log(LOG_WARNING, "The application delimiter is now the comma, not "
01586 "the pipe. Did you forget to convert your dialplan? (%s(%s))\n",
01587 app->name, (char *) data);
01588 }
01589 res = app->execute(c, S_OR(data, ""));
01590 if (app->module && u)
01591 __ast_module_user_remove(app->module, u);
01592 ast_cel_report_event(c, AST_CEL_APP_END, NULL, NULL, NULL);
01593
01594 ast_channel_appl_set(c, saved_c_appl);
01595 ast_channel_data_set(c, saved_c_data);
01596 return res;
01597 }
01598
01599
01600
01601 #define AST_PBX_MAX_STACK 128
01602
01603
01604
01605 struct ast_app *pbx_findapp(const char *app)
01606 {
01607 struct ast_app *tmp;
01608
01609 AST_RWLIST_RDLOCK(&apps);
01610 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
01611 if (!strcasecmp(tmp->name, app))
01612 break;
01613 }
01614 AST_RWLIST_UNLOCK(&apps);
01615
01616 return tmp;
01617 }
01618
01619 static struct ast_switch *pbx_findswitch(const char *sw)
01620 {
01621 struct ast_switch *asw;
01622
01623 AST_RWLIST_RDLOCK(&switches);
01624 AST_RWLIST_TRAVERSE(&switches, asw, list) {
01625 if (!strcasecmp(asw->name, sw))
01626 break;
01627 }
01628 AST_RWLIST_UNLOCK(&switches);
01629
01630 return asw;
01631 }
01632
01633 static inline int include_valid(struct ast_include *i)
01634 {
01635 if (!i->hastime)
01636 return 1;
01637
01638 return ast_check_timing(&(i->timing));
01639 }
01640
01641 static void pbx_destroy(struct ast_pbx *p)
01642 {
01643 ast_free(p);
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
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 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)
01721 {
01722
01723
01724 if (deleted)
01725 return;
01726 board->total_specificity = spec;
01727 board->total_length = length;
01728 board->exten = exten;
01729 board->last_char = last;
01730 board->node = node;
01731 #ifdef NEED_DEBUG_HERE
01732 ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
01733 #endif
01734 }
01735
01736 #ifdef NEED_DEBUG
01737 static void log_match_char_tree(struct match_char *node, char *prefix)
01738 {
01739 char extenstr[40];
01740 struct ast_str *my_prefix = ast_str_alloca(1024);
01741
01742 extenstr[0] = '\0';
01743
01744 if (node && node->exten)
01745 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01746
01747 if (strlen(node->x) > 1) {
01748 ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
01749 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
01750 node->exten ? node->exten->exten : "", extenstr);
01751 } else {
01752 ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
01753 node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
01754 node->exten ? node->exten->exten : "", extenstr);
01755 }
01756
01757 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
01758
01759 if (node->next_char)
01760 log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
01761
01762 if (node->alt_char)
01763 log_match_char_tree(node->alt_char, prefix);
01764 }
01765 #endif
01766
01767 static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
01768 {
01769 char extenstr[40];
01770 struct ast_str *my_prefix = ast_str_alloca(1024);
01771
01772 extenstr[0] = '\0';
01773
01774 if (node->exten) {
01775 snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01776 }
01777
01778 if (strlen(node->x) > 1) {
01779 ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
01780 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
01781 node->exten ? node->exten->exten : "", extenstr);
01782 } else {
01783 ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
01784 node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
01785 node->exten ? node->exten->exten : "", extenstr);
01786 }
01787
01788 ast_str_set(&my_prefix, 0, "%s+ ", prefix);
01789
01790 if (node->next_char)
01791 cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
01792
01793 if (node->alt_char)
01794 cli_match_char_tree(node->alt_char, prefix, fd);
01795 }
01796
01797 static struct ast_exten *get_canmatch_exten(struct match_char *node)
01798 {
01799
01800 struct match_char *node2 = node;
01801
01802 for (node2 = node; node2; node2 = node2->next_char) {
01803 if (node2->exten) {
01804 #ifdef NEED_DEBUG_HERE
01805 ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
01806 #endif
01807 return node2->exten;
01808 }
01809 }
01810 #ifdef NEED_DEBUG_HERE
01811 ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
01812 #endif
01813 return 0;
01814 }
01815
01816 static struct ast_exten *trie_find_next_match(struct match_char *node)
01817 {
01818 struct match_char *m3;
01819 struct match_char *m4;
01820 struct ast_exten *e3;
01821
01822 if (node && node->x[0] == '.' && !node->x[1]) {
01823 return node->exten;
01824 }
01825
01826 if (node && node->x[0] == '!' && !node->x[1]) {
01827 return node->exten;
01828 }
01829
01830 if (!node || !node->next_char) {
01831 return NULL;
01832 }
01833
01834 m3 = node->next_char;
01835
01836 if (m3->exten) {
01837 return m3->exten;
01838 }
01839 for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
01840 if (m4->exten) {
01841 return m4->exten;
01842 }
01843 }
01844 for (m4 = m3; m4; m4 = m4->alt_char) {
01845 e3 = trie_find_next_match(m3);
01846 if (e3) {
01847 return e3;
01848 }
01849 }
01850
01851 return NULL;
01852 }
01853
01854 #ifdef DEBUG_THIS
01855 static char *action2str(enum ext_match_t action)
01856 {
01857 switch (action) {
01858 case E_MATCH:
01859 return "MATCH";
01860 case E_CANMATCH:
01861 return "CANMATCH";
01862 case E_MATCHMORE:
01863 return "MATCHMORE";
01864 case E_FINDLABEL:
01865 return "FINDLABEL";
01866 case E_SPAWN:
01867 return "SPAWN";
01868 default:
01869 return "?ACTION?";
01870 }
01871 }
01872
01873 #endif
01874
01875 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)
01876 {
01877 struct match_char *p;
01878 struct ast_exten pattern = { .label = label };
01879 #ifdef DEBUG_THIS
01880 if (tree)
01881 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
01882 else
01883 ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
01884 #endif
01885 for (p = tree; p; p = p->alt_char) {
01886 if (p->is_pattern) {
01887 if (p->x[0] == 'N') {
01888 if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
01889 #define NEW_MATCHER_CHK_MATCH \
01890 if (p->exten && !(*(str + 1))) { \
01891 if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { \
01892 update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p); \
01893 if (!p->deleted) { \
01894 if (action == E_FINDLABEL) { \
01895 if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) { \
01896 ast_debug(4, "Found label in preferred extension\n"); \
01897 return; \
01898 } \
01899 } else { \
01900 ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten); \
01901 return; \
01902 } \
01903 } \
01904 } \
01905 }
01906
01907 #define NEW_MATCHER_RECURSE \
01908 if (p->next_char && (*(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0) \
01909 || p->next_char->x[0] == '!')) { \
01910 if (*(str + 1) || p->next_char->x[0] == '!') { \
01911 new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
01912 if (score->exten) { \
01913 ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten); \
01914 return; \
01915 } \
01916 } else { \
01917 new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
01918 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
01919 ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \
01920 "NULL"); \
01921 return; \
01922 } \
01923 } \
01924 } else if ((p->next_char || action == E_CANMATCH) && !*(str + 1)) { \
01925 score->canmatch = 1; \
01926 score->canmatch_exten = get_canmatch_exten(p); \
01927 if (action == E_CANMATCH || action == E_MATCHMORE) { \
01928 ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str); \
01929 return; \
01930 } \
01931 }
01932
01933 NEW_MATCHER_CHK_MATCH;
01934 NEW_MATCHER_RECURSE;
01935 }
01936 } else if (p->x[0] == 'Z') {
01937 if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
01938 NEW_MATCHER_CHK_MATCH;
01939 NEW_MATCHER_RECURSE;
01940 }
01941 } else if (p->x[0] == 'X') {
01942 if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
01943 NEW_MATCHER_CHK_MATCH;
01944 NEW_MATCHER_RECURSE;
01945 }
01946 } else if (p->x[0] == '.' && p->x[1] == 0) {
01947
01948 int i = 0;
01949 const char *str2 = str;
01950 while (*str2 && *str2 != '/') {
01951 str2++;
01952 i++;
01953 }
01954 if (p->exten && *str2 != '/') {
01955 update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
01956 if (score->exten) {
01957 ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
01958 return;
01959 }
01960 }
01961 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01962 new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
01963 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01964 ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
01965 return;
01966 }
01967 }
01968 } else if (p->x[0] == '!' && p->x[1] == 0) {
01969
01970 int i = 1;
01971 const char *str2 = str;
01972 while (*str2 && *str2 != '/') {
01973 str2++;
01974 i++;
01975 }
01976 if (p->exten && *str2 != '/') {
01977 update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
01978 if (score->exten) {
01979 ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
01980 return;
01981 }
01982 }
01983 if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01984 new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
01985 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01986 ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
01987 return;
01988 }
01989 }
01990 } else if (p->x[0] == '/' && p->x[1] == 0) {
01991
01992 if (p->next_char && callerid && *callerid) {
01993 new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
01994 if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01995 ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
01996 return;
01997 }
01998 }
01999 } else if (strchr(p->x, *str)) {
02000 ast_debug(4, "Nothing strange about this match\n");
02001 NEW_MATCHER_CHK_MATCH;
02002 NEW_MATCHER_RECURSE;
02003 }
02004 } else if (strchr(p->x, *str)) {
02005 ast_debug(4, "Nothing strange about this match\n");
02006 NEW_MATCHER_CHK_MATCH;
02007 NEW_MATCHER_RECURSE;
02008 }
02009 }
02010 ast_debug(4, "return at end of func\n");
02011 }
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030 static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
02031 {
02032 struct match_char *t;
02033
02034 if (!current) {
02035 return 0;
02036 }
02037
02038 for (t = current; t; t = t->alt_char) {
02039 if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {
02040 return t;
02041 }
02042 }
02043
02044 return 0;
02045 }
02046
02047
02048
02049
02050
02051 static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
02052 {
02053 struct match_char *curr, *lcurr;
02054
02055
02056
02057 if (!(*parent_ptr)) {
02058 *parent_ptr = node;
02059 return;
02060 }
02061
02062 if ((*parent_ptr)->specificity > node->specificity) {
02063
02064 node->alt_char = (*parent_ptr);
02065 *parent_ptr = node;
02066 return;
02067 }
02068
02069 lcurr = *parent_ptr;
02070 for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
02071 if (curr->specificity > node->specificity) {
02072 node->alt_char = curr;
02073 lcurr->alt_char = node;
02074 break;
02075 }
02076 lcurr = curr;
02077 }
02078
02079 if (!curr) {
02080 lcurr->alt_char = node;
02081 }
02082
02083 }
02084
02085 struct pattern_node {
02086
02087 int specif;
02088
02089 char buf[256];
02090 };
02091
02092 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)
02093 {
02094 struct match_char *m;
02095
02096 if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern->buf)))) {
02097 return NULL;
02098 }
02099
02100
02101
02102
02103 strcpy(m->x, pattern->buf);
02104
02105
02106
02107 m->is_pattern = is_pattern;
02108 if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'N') {
02109 m->specificity = 0x0832;
02110 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'Z') {
02111 m->specificity = 0x0931;
02112 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == 'X') {
02113 m->specificity = 0x0a30;
02114 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '.') {
02115 m->specificity = 0x18000;
02116 } else if (pattern->specif == 1 && is_pattern && pattern->buf[0] == '!') {
02117 m->specificity = 0x28000;
02118 } else {
02119 m->specificity = pattern->specif;
02120 }
02121
02122 if (!con->pattern_tree) {
02123 insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
02124 } else {
02125 if (already) {
02126 insert_in_next_chars_alt_char_list(nextcharptr, m);
02127 } else {
02128 insert_in_next_chars_alt_char_list(¤t->next_char, m);
02129 }
02130 }
02131
02132 return m;
02133 }
02134
02135
02136
02137
02138
02139
02140
02141
02142
02143
02144
02145
02146 static const char *get_pattern_node(struct pattern_node *node, const char *src, int pattern, const char *extenbuf)
02147 {
02148 #define INC_DST_OVERFLOW_CHECK \
02149 do { \
02150 if (dst - node->buf < sizeof(node->buf) - 1) { \
02151 ++dst; \
02152 } else { \
02153 overflow = 1; \
02154 } \
02155 } while (0)
02156
02157 node->specif = 0;
02158 node->buf[0] = '\0';
02159 while (*src) {
02160 if (*src == '[' && pattern) {
02161 char *dst = node->buf;
02162 const char *src_next;
02163 int length;
02164 int overflow = 0;
02165
02166
02167 ++src;
02168 for (;;) {
02169 if (*src == '\\') {
02170
02171 ++src;
02172 if (*src == '[' || *src == '\\' || *src == '-' || *src == ']') {
02173 *dst = *src++;
02174 INC_DST_OVERFLOW_CHECK;
02175 }
02176 } else if (*src == '-') {
02177 unsigned char first;
02178 unsigned char last;
02179
02180 src_next = src;
02181 first = *(src_next - 1);
02182 last = *++src_next;
02183
02184 if (last == '\\') {
02185
02186 last = *++src_next;
02187 }
02188
02189
02190 if (node->buf[0] && last) {
02191
02192 while (++first <= last) {
02193 *dst = first;
02194 INC_DST_OVERFLOW_CHECK;
02195 }
02196 src = src_next + 1;
02197 } else {
02198
02199
02200
02201
02202 *dst = *src++;
02203 INC_DST_OVERFLOW_CHECK;
02204 }
02205 } else if (*src == '\0') {
02206 ast_log(LOG_WARNING,
02207 "A matching ']' was not found for '[' in exten pattern '%s'\n",
02208 extenbuf);
02209 break;
02210 } else if (*src == ']') {
02211 ++src;
02212 break;
02213 } else {
02214 *dst = *src++;
02215 INC_DST_OVERFLOW_CHECK;
02216 }
02217 }
02218
02219 *dst = '\0';
02220
02221 if (overflow) {
02222 ast_log(LOG_ERROR,
02223 "Expanded character set too large to deal with in exten pattern '%s'. Ignoring character set.\n",
02224 extenbuf);
02225 node->buf[0] = '\0';
02226 continue;
02227 }
02228
02229
02230 length = strlen(node->buf);
02231 if (!length) {
02232 ast_log(LOG_WARNING, "Empty character set in exten pattern '%s'. Ignoring.\n",
02233 extenbuf);
02234 node->buf[0] = '\0';
02235 continue;
02236 }
02237 qsort(node->buf, length, 1, compare_char);
02238
02239
02240 dst = node->buf;
02241 src_next = node->buf;
02242 while (*src_next++) {
02243 if (*dst != *src_next) {
02244 *++dst = *src_next;
02245 }
02246 }
02247
02248 length = strlen(node->buf);
02249 length <<= 8;
02250 node->specif = length | (unsigned char) node->buf[0];
02251 break;
02252 } else if (*src == '-') {
02253
02254 ++src;
02255 } else {
02256 if (*src == '\\') {
02257
02258
02259
02260
02261
02262 node->buf[0] = *++src;
02263 if (!node->buf[0]) {
02264 break;
02265 }
02266 } else {
02267 node->buf[0] = *src;
02268 if (pattern) {
02269
02270 if (node->buf[0] == 'n') {
02271 node->buf[0] = 'N';
02272 } else if (node->buf[0] == 'x') {
02273 node->buf[0] = 'X';
02274 } else if (node->buf[0] == 'z') {
02275 node->buf[0] = 'Z';
02276 }
02277 }
02278 }
02279 node->buf[1] = '\0';
02280 node->specif = 1;
02281 ++src;
02282 break;
02283 }
02284 }
02285 return src;
02286
02287 #undef INC_DST_OVERFLOW_CHECK
02288 }
02289
02290 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
02291 {
02292 struct match_char *m1 = NULL;
02293 struct match_char *m2 = NULL;
02294 struct match_char **m0;
02295 const char *pos;
02296 int already;
02297 int pattern = 0;
02298 int idx_cur;
02299 int idx_next;
02300 char extenbuf[512];
02301 struct pattern_node pat_node[2];
02302
02303 if (e1->matchcid) {
02304 if (sizeof(extenbuf) < strlen(e1->exten) + strlen(e1->cidmatch) + 2) {
02305 ast_log(LOG_ERROR,
02306 "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n",
02307 e1->exten, e1->cidmatch);
02308 return NULL;
02309 }
02310 sprintf(extenbuf, "%s/%s", e1->exten, e1->cidmatch);
02311 } else {
02312 ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
02313 }
02314
02315 #ifdef NEED_DEBUG
02316 ast_debug(1, "Adding exten %s to tree\n", extenbuf);
02317 #endif
02318 m1 = con->pattern_tree;
02319 m0 = &con->pattern_tree;
02320 already = 1;
02321
02322 pos = extenbuf;
02323 if (*pos == '_') {
02324 pattern = 1;
02325 ++pos;
02326 }
02327 idx_cur = 0;
02328 pos = get_pattern_node(&pat_node[idx_cur], pos, pattern, extenbuf);
02329 for (; pat_node[idx_cur].buf[0]; idx_cur = idx_next) {
02330 idx_next = (idx_cur + 1) % ARRAY_LEN(pat_node);
02331 pos = get_pattern_node(&pat_node[idx_next], pos, pattern, extenbuf);
02332
02333
02334 m2 = NULL;
02335 if (already && (m2 = already_in_tree(m1, pat_node[idx_cur].buf, pattern))
02336 && m2->next_char) {
02337 if (!pat_node[idx_next].buf[0]) {
02338
02339
02340
02341
02342
02343 if (findonly) {
02344 return m2;
02345 }
02346 if (m2->exten) {
02347 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
02348 m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
02349 }
02350 m2->exten = e1;
02351 m2->deleted = 0;
02352 }
02353 m1 = m2->next_char;
02354 m0 = &m2->next_char;
02355 } else {
02356 if (m2) {
02357 if (findonly) {
02358 return m2;
02359 }
02360 m1 = m2;
02361 } else {
02362 if (findonly) {
02363 return m1;
02364 }
02365 m1 = add_pattern_node(con, m1, &pat_node[idx_cur], pattern, already, m0);
02366 if (!m1) {
02367 return NULL;
02368 }
02369 m0 = &m1->next_char;
02370 }
02371 if (!pat_node[idx_next].buf[0]) {
02372 if (m2 && m2->exten) {
02373 ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
02374 m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
02375 }
02376 m1->deleted = 0;
02377 m1->exten = e1;
02378 }
02379
02380
02381
02382
02383 already = 0;
02384 }
02385 }
02386 return m1;
02387 }
02388
02389 static void create_match_char_tree(struct ast_context *con)
02390 {
02391 struct ast_hashtab_iter *t1;
02392 struct ast_exten *e1;
02393 #ifdef NEED_DEBUG
02394 int biggest_bucket, resizes, numobjs, numbucks;
02395
02396 ast_debug(1, "Creating Extension Trie for context %s(%p)\n", con->name, con);
02397 ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
02398 ast_debug(1, "This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
02399 numobjs, numbucks, biggest_bucket, resizes);
02400 #endif
02401 t1 = ast_hashtab_start_traversal(con->root_table);
02402 while ((e1 = ast_hashtab_next(t1))) {
02403 if (e1->exten) {
02404 add_exten_to_pattern_tree(con, e1, 0);
02405 } else {
02406 ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
02407 }
02408 }
02409 ast_hashtab_end_traversal(t1);
02410 }
02411
02412 static void destroy_pattern_tree(struct match_char *pattern_tree)
02413 {
02414
02415 if (pattern_tree->alt_char) {
02416 destroy_pattern_tree(pattern_tree->alt_char);
02417 pattern_tree->alt_char = 0;
02418 }
02419
02420 if (pattern_tree->next_char) {
02421 destroy_pattern_tree(pattern_tree->next_char);
02422 pattern_tree->next_char = 0;
02423 }
02424 pattern_tree->exten = 0;
02425 ast_free(pattern_tree);
02426 }
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465
02466
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481
02482 static int ext_cmp1(const char **p, unsigned char *bitwise)
02483 {
02484 int c, cmin = 0xff, count = 0;
02485 const char *end;
02486
02487
02488 c = *(*p)++;
02489
02490
02491 switch (toupper(c)) {
02492 default:
02493 bitwise[c / 8] = 1 << (c % 8);
02494 return 0x0100 | (c & 0xff);
02495
02496 case 'N':
02497 bitwise[6] = 0xfc;
02498 bitwise[7] = 0x03;
02499 return 0x0800 | '2';
02500
02501 case 'X':
02502 bitwise[6] = 0xff;
02503 bitwise[7] = 0x03;
02504 return 0x0A00 | '0';
02505
02506 case 'Z':
02507 bitwise[6] = 0xfe;
02508 bitwise[7] = 0x03;
02509 return 0x0900 | '1';
02510
02511 case '.':
02512 return 0x18000;
02513
02514 case '!':
02515 return 0x28000;
02516
02517 case '\0':
02518 *p = NULL;
02519 return 0x30000;
02520
02521 case '[':
02522 break;
02523 }
02524
02525 end = strchr(*p, ']');
02526
02527 if (end == NULL) {
02528 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02529 return 0x40000;
02530 }
02531
02532 for (; *p < end ; (*p)++) {
02533 unsigned char c1, c2;
02534 c1 = (unsigned char)((*p)[0]);
02535 if (*p + 2 < end && (*p)[1] == '-') {
02536 c2 = (unsigned char)((*p)[2]);
02537 *p += 2;
02538 } else {
02539 c2 = c1;
02540 }
02541 if (c1 < cmin) {
02542 cmin = c1;
02543 }
02544 for (; c1 <= c2; c1++) {
02545 unsigned char mask = 1 << (c1 % 8);
02546
02547
02548
02549 if (!(bitwise[ c1 / 8 ] & mask)) {
02550 bitwise[ c1 / 8 ] |= mask;
02551 count += 0x100;
02552 }
02553 }
02554 }
02555 (*p)++;
02556 return count == 0 ? 0x30000 : (count | cmin);
02557 }
02558
02559
02560
02561
02562 static int ext_cmp(const char *a, const char *b)
02563 {
02564
02565
02566
02567
02568 int ret = 0;
02569
02570 if (a[0] != '_')
02571 return (b[0] == '_') ? -1 : strcmp(a, b);
02572
02573
02574 if (b[0] != '_')
02575 return 1;
02576
02577
02578
02579 ++a; ++b;
02580 do {
02581 unsigned char bitwise[2][32] = { { 0, } };
02582 ret = ext_cmp1(&a, bitwise[0]) - ext_cmp1(&b, bitwise[1]);
02583 if (ret == 0) {
02584
02585 ret = memcmp(bitwise[0], bitwise[1], 32);
02586 }
02587 } while (!ret && a && b);
02588 if (ret == 0) {
02589 return 0;
02590 } else {
02591 return (ret > 0) ? 1 : -1;
02592 }
02593 }
02594
02595 int ast_extension_cmp(const char *a, const char *b)
02596 {
02597 return ext_cmp(a, b);
02598 }
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
02612 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
02613 {
02614 mode &= E_MATCH_MASK;
02615
02616 #ifdef NEED_DEBUG_HERE
02617 ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
02618 #endif
02619
02620 if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) {
02621 #ifdef NEED_DEBUG_HERE
02622 ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
02623 #endif
02624 return 1;
02625 }
02626
02627 if (pattern[0] != '_') {
02628 int ld = strlen(data), lp = strlen(pattern);
02629
02630 if (lp < ld) {
02631 #ifdef NEED_DEBUG_HERE
02632 ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
02633 #endif
02634 return 0;
02635 }
02636
02637 if (mode == E_MATCH) {
02638 #ifdef NEED_DEBUG_HERE
02639 ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
02640 #endif
02641 return !strcmp(pattern, data);
02642 }
02643 if (ld == 0 || !strncasecmp(pattern, data, ld)) {
02644 #ifdef NEED_DEBUG_HERE
02645 ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
02646 #endif
02647 return (mode == E_MATCHMORE) ? lp > ld : 1;
02648 } else {
02649 #ifdef NEED_DEBUG_HERE
02650 ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
02651 #endif
02652 return 0;
02653 }
02654 }
02655 pattern++;
02656
02657
02658
02659
02660 while (*data && *pattern && *pattern != '/') {
02661 const char *end;
02662
02663 if (*data == '-') {
02664 data++;
02665 continue;
02666 }
02667 switch (toupper(*pattern)) {
02668 case '[':
02669 end = strchr(pattern+1, ']');
02670 if (end == NULL) {
02671 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02672 return 0;
02673 }
02674 for (pattern++; pattern != end; pattern++) {
02675 if (pattern+2 < end && pattern[1] == '-') {
02676 if (*data >= pattern[0] && *data <= pattern[2])
02677 break;
02678 else {
02679 pattern += 2;
02680 continue;
02681 }
02682 } else if (*data == pattern[0])
02683 break;
02684 }
02685 if (pattern == end) {
02686 #ifdef NEED_DEBUG_HERE
02687 ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
02688 #endif
02689 return 0;
02690 }
02691 pattern = end;
02692 break;
02693 case 'N':
02694 if (*data < '2' || *data > '9') {
02695 #ifdef NEED_DEBUG_HERE
02696 ast_log(LOG_NOTICE,"return (0) N is matched\n");
02697 #endif
02698 return 0;
02699 }
02700 break;
02701 case 'X':
02702 if (*data < '0' || *data > '9') {
02703 #ifdef NEED_DEBUG_HERE
02704 ast_log(LOG_NOTICE,"return (0) X is matched\n");
02705 #endif
02706 return 0;
02707 }
02708 break;
02709 case 'Z':
02710 if (*data < '1' || *data > '9') {
02711 #ifdef NEED_DEBUG_HERE
02712 ast_log(LOG_NOTICE,"return (0) Z is matched\n");
02713 #endif
02714 return 0;
02715 }
02716 break;
02717 case '.':
02718 #ifdef NEED_DEBUG_HERE
02719 ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
02720 #endif
02721 return 1;
02722 case '!':
02723 #ifdef NEED_DEBUG_HERE
02724 ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
02725 #endif
02726 return 2;
02727 case ' ':
02728 case '-':
02729 data--;
02730 break;
02731 default:
02732 if (*data != *pattern) {
02733 #ifdef NEED_DEBUG_HERE
02734 ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
02735 #endif
02736 return 0;
02737 }
02738 }
02739 data++;
02740 pattern++;
02741 }
02742 if (*data) {
02743 #ifdef NEED_DEBUG_HERE
02744 ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
02745 #endif
02746 return 0;
02747 }
02748
02749
02750
02751
02752
02753 if (*pattern == '\0' || *pattern == '/') {
02754 #ifdef NEED_DEBUG_HERE
02755 ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
02756 #endif
02757 return (mode == E_MATCHMORE) ? 0 : 1;
02758 } else if (*pattern == '!') {
02759 #ifdef NEED_DEBUG_HERE
02760 ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
02761 #endif
02762 return 2;
02763 } else {
02764 #ifdef NEED_DEBUG_HERE
02765 ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
02766 #endif
02767 return (mode == E_MATCH) ? 0 : 1;
02768 }
02769 }
02770
02771
02772
02773
02774
02775 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
02776 {
02777 int i;
02778 static int prof_id = -2;
02779 if (prof_id == -2) {
02780 prof_id = ast_add_profile("ext_match", 0);
02781 }
02782 ast_mark(prof_id, 1);
02783 i = _extension_match_core(ast_strlen_zero(pattern) ? "" : pattern, ast_strlen_zero(data) ? "" : data, mode);
02784 ast_mark(prof_id, 0);
02785 return i;
02786 }
02787
02788 int ast_extension_match(const char *pattern, const char *data)
02789 {
02790 return extension_match_core(pattern, data, E_MATCH);
02791 }
02792
02793 int ast_extension_close(const char *pattern, const char *data, int needmore)
02794 {
02795 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
02796 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
02797 return extension_match_core(pattern, data, needmore);
02798 }
02799
02800 struct fake_context
02801 {
02802 ast_rwlock_t lock;
02803 struct ast_exten *root;
02804 struct ast_hashtab *root_table;
02805 struct match_char *pattern_tree;
02806 struct ast_context *next;
02807 struct ast_include *includes;
02808 struct ast_ignorepat *ignorepats;
02809 const char *registrar;
02810 int refcount;
02811 AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
02812 ast_mutex_t macrolock;
02813 char name[256];
02814 };
02815
02816 struct ast_context *ast_context_find(const char *name)
02817 {
02818 struct ast_context *tmp;
02819 struct fake_context item;
02820
02821 if (!name) {
02822 return NULL;
02823 }
02824 ast_rdlock_contexts();
02825 if (contexts_table) {
02826 ast_copy_string(item.name, name, sizeof(item.name));
02827 tmp = ast_hashtab_lookup(contexts_table, &item);
02828 } else {
02829 tmp = NULL;
02830 while ((tmp = ast_walk_contexts(tmp))) {
02831 if (!strcasecmp(name, tmp->name)) {
02832 break;
02833 }
02834 }
02835 }
02836 ast_unlock_contexts();
02837 return tmp;
02838 }
02839
02840 #define STATUS_NO_CONTEXT 1
02841 #define STATUS_NO_EXTENSION 2
02842 #define STATUS_NO_PRIORITY 3
02843 #define STATUS_NO_LABEL 4
02844 #define STATUS_SUCCESS 5
02845
02846 static int matchcid(const char *cidpattern, const char *callerid)
02847 {
02848
02849
02850
02851 if (ast_strlen_zero(callerid)) {
02852 return ast_strlen_zero(cidpattern) ? 1 : 0;
02853 }
02854
02855 return ast_extension_match(cidpattern, callerid);
02856 }
02857
02858 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
02859 struct ast_context *bypass, struct pbx_find_info *q,
02860 const char *context, const char *exten, int priority,
02861 const char *label, const char *callerid, enum ext_match_t action)
02862 {
02863 int x, res;
02864 struct ast_context *tmp = NULL;
02865 struct ast_exten *e = NULL, *eroot = NULL;
02866 struct ast_include *i = NULL;
02867 struct ast_sw *sw = NULL;
02868 struct ast_exten pattern = {NULL, };
02869 struct scoreboard score = {0, };
02870 struct ast_str *tmpdata = NULL;
02871
02872 pattern.label = label;
02873 pattern.priority = priority;
02874 #ifdef NEED_DEBUG_HERE
02875 ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
02876 #endif
02877
02878
02879 if (q->stacklen == 0) {
02880 q->status = STATUS_NO_CONTEXT;
02881 q->swo = NULL;
02882 q->data = NULL;
02883 q->foundcontext = NULL;
02884 } else if (q->stacklen >= AST_PBX_MAX_STACK) {
02885 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
02886 return NULL;
02887 }
02888
02889
02890 for (x = 0; x < q->stacklen; x++) {
02891 if (!strcasecmp(q->incstack[x], context))
02892 return NULL;
02893 }
02894
02895 if (bypass) {
02896 tmp = bypass;
02897 } else {
02898 tmp = find_context(context);
02899 if (!tmp) {
02900 return NULL;
02901 }
02902 }
02903
02904 if (q->status < STATUS_NO_EXTENSION)
02905 q->status = STATUS_NO_EXTENSION;
02906
02907
02908
02909 eroot = NULL;
02910 score.total_specificity = 0;
02911 score.exten = 0;
02912 score.total_length = 0;
02913 if (!tmp->pattern_tree && tmp->root_table) {
02914 create_match_char_tree(tmp);
02915 #ifdef NEED_DEBUG
02916 ast_debug(1, "Tree Created in context %s:\n", context);
02917 log_match_char_tree(tmp->pattern_tree," ");
02918 #endif
02919 }
02920 #ifdef NEED_DEBUG
02921 ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
02922 log_match_char_tree(tmp->pattern_tree, ":: ");
02923 #endif
02924
02925 do {
02926 if (!ast_strlen_zero(overrideswitch)) {
02927 char *osw = ast_strdupa(overrideswitch), *name;
02928 struct ast_switch *asw;
02929 ast_switch_f *aswf = NULL;
02930 char *datap;
02931 int eval = 0;
02932
02933 name = strsep(&osw, "/");
02934 asw = pbx_findswitch(name);
02935
02936 if (!asw) {
02937 ast_log(LOG_WARNING, "No such switch '%s'\n", name);
02938 break;
02939 }
02940
02941 if (osw && strchr(osw, '$')) {
02942 eval = 1;
02943 }
02944
02945 if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02946 ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!\n");
02947 break;
02948 } else if (eval) {
02949
02950 pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
02951 datap = ast_str_buffer(tmpdata);
02952 } else {
02953 datap = osw;
02954 }
02955
02956
02957 if (action == E_CANMATCH)
02958 aswf = asw->canmatch;
02959 else if (action == E_MATCHMORE)
02960 aswf = asw->matchmore;
02961 else
02962 aswf = asw->exists;
02963 if (!aswf) {
02964 res = 0;
02965 } else {
02966 if (chan) {
02967 ast_autoservice_start(chan);
02968 }
02969 res = aswf(chan, context, exten, priority, callerid, datap);
02970 if (chan) {
02971 ast_autoservice_stop(chan);
02972 }
02973 }
02974 if (res) {
02975 q->swo = asw;
02976 q->data = datap;
02977 q->foundcontext = context;
02978
02979 return NULL;
02980 }
02981 }
02982 } while (0);
02983
02984 if (extenpatternmatchnew) {
02985 new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
02986 eroot = score.exten;
02987
02988 if (score.last_char == '!' && action == E_MATCHMORE) {
02989
02990
02991
02992 #ifdef NEED_DEBUG_HERE
02993 ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
02994 #endif
02995 return NULL;
02996 }
02997
02998 if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
02999 q->status = STATUS_SUCCESS;
03000 #ifdef NEED_DEBUG_HERE
03001 ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
03002 #endif
03003 return score.canmatch_exten;
03004 }
03005
03006 if ((action == E_MATCHMORE || action == E_CANMATCH) && eroot) {
03007 if (score.node) {
03008 struct ast_exten *z = trie_find_next_match(score.node);
03009 if (z) {
03010 #ifdef NEED_DEBUG_HERE
03011 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
03012 #endif
03013 } else {
03014 if (score.canmatch_exten) {
03015 #ifdef NEED_DEBUG_HERE
03016 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
03017 #endif
03018 return score.canmatch_exten;
03019 } else {
03020 #ifdef NEED_DEBUG_HERE
03021 ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
03022 #endif
03023 }
03024 }
03025 return z;
03026 }
03027 #ifdef NEED_DEBUG_HERE
03028 ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
03029 #endif
03030 return NULL;
03031 }
03032
03033 if (eroot) {
03034
03035 if (q->status < STATUS_NO_PRIORITY)
03036 q->status = STATUS_NO_PRIORITY;
03037 e = NULL;
03038 if (action == E_FINDLABEL && label ) {
03039 if (q->status < STATUS_NO_LABEL)
03040 q->status = STATUS_NO_LABEL;
03041 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
03042 } else {
03043 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
03044 }
03045 if (e) {
03046 q->status = STATUS_SUCCESS;
03047 q->foundcontext = context;
03048 #ifdef NEED_DEBUG_HERE
03049 ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
03050 #endif
03051 return e;
03052 }
03053 }
03054 } else {
03055
03056
03057 eroot = NULL;
03058 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
03059 int match = extension_match_core(eroot->exten, exten, action);
03060
03061
03062 if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
03063 continue;
03064 if (match == 2 && action == E_MATCHMORE) {
03065
03066
03067
03068 return NULL;
03069 }
03070
03071 if (q->status < STATUS_NO_PRIORITY)
03072 q->status = STATUS_NO_PRIORITY;
03073 e = NULL;
03074 if (action == E_FINDLABEL && label ) {
03075 if (q->status < STATUS_NO_LABEL)
03076 q->status = STATUS_NO_LABEL;
03077 e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
03078 } else {
03079 e = ast_hashtab_lookup(eroot->peer_table, &pattern);
03080 }
03081 if (e) {
03082 q->status = STATUS_SUCCESS;
03083 q->foundcontext = context;
03084 return e;
03085 }
03086 }
03087 }
03088
03089
03090 AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
03091 struct ast_switch *asw = pbx_findswitch(sw->name);
03092 ast_switch_f *aswf = NULL;
03093 char *datap;
03094
03095 if (!asw) {
03096 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
03097 continue;
03098 }
03099
03100
03101 if (sw->eval) {
03102 if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
03103 ast_log(LOG_WARNING, "Can't evaluate switch?!\n");
03104 continue;
03105 }
03106 pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
03107 }
03108
03109
03110 if (action == E_CANMATCH)
03111 aswf = asw->canmatch;
03112 else if (action == E_MATCHMORE)
03113 aswf = asw->matchmore;
03114 else
03115 aswf = asw->exists;
03116 datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
03117 if (!aswf)
03118 res = 0;
03119 else {
03120 if (chan)
03121 ast_autoservice_start(chan);
03122 res = aswf(chan, context, exten, priority, callerid, datap);
03123 if (chan)
03124 ast_autoservice_stop(chan);
03125 }
03126 if (res) {
03127 q->swo = asw;
03128 q->data = datap;
03129 q->foundcontext = context;
03130
03131 return NULL;
03132 }
03133 }
03134 q->incstack[q->stacklen++] = tmp->name;
03135
03136 for (i = tmp->includes; i; i = i->next) {
03137 if (include_valid(i)) {
03138 if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
03139 #ifdef NEED_DEBUG_HERE
03140 ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
03141 #endif
03142 return e;
03143 }
03144 if (q->swo)
03145 return NULL;
03146 }
03147 }
03148 return NULL;
03149 }
03150
03151
03152
03153
03154
03155
03156 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
03157 {
03158 int parens = 0;
03159
03160 *offset = 0;
03161 *length = INT_MAX;
03162 *isfunc = 0;
03163 for (; *var; var++) {
03164 if (*var == '(') {
03165 (*isfunc)++;
03166 parens++;
03167 } else if (*var == ')') {
03168 parens--;
03169 } else if (*var == ':' && parens == 0) {
03170 *var++ = '\0';
03171 sscanf(var, "%30d:%30d", offset, length);
03172 return 1;
03173 }
03174 }
03175 return 0;
03176 }
03177
03178
03179
03180
03181
03182
03183
03184
03185
03186
03187
03188
03189 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
03190 {
03191 char *ret = workspace;
03192 int lr;
03193
03194 ast_copy_string(workspace, value, workspace_len);
03195
03196 lr = strlen(ret);
03197
03198
03199 if (offset == 0 && length >= lr)
03200 return ret;
03201
03202 if (offset < 0) {
03203 offset = lr + offset;
03204 if (offset < 0)
03205 offset = 0;
03206 }
03207
03208
03209 if (offset >= lr)
03210 return ret + lr;
03211
03212 ret += offset;
03213 if (length >= 0 && length < lr - offset)
03214 ret[length] = '\0';
03215 else if (length < 0) {
03216 if (lr > offset - length)
03217 ret[lr + length - offset] = '\0';
03218 else
03219 ret[0] = '\0';
03220 }
03221
03222 return ret;
03223 }
03224
03225 static const char *ast_str_substring(struct ast_str *value, int offset, int length)
03226 {
03227 int lr;
03228
03229 lr = ast_str_strlen(value);
03230
03231
03232 if (offset == 0 && length >= lr)
03233 return ast_str_buffer(value);
03234
03235 if (offset < 0) {
03236 offset = lr + offset;
03237 if (offset < 0)
03238 offset = 0;
03239 }
03240
03241
03242 if (offset >= lr) {
03243 ast_str_reset(value);
03244 return ast_str_buffer(value);
03245 }
03246
03247 if (offset > 0) {
03248
03249 memmove(ast_str_buffer(value), ast_str_buffer(value) + offset, ast_str_strlen(value) - offset + 1);
03250 lr -= offset;
03251 }
03252
03253 if (length >= 0 && length < lr) {
03254 char *tmp = ast_str_buffer(value);
03255 tmp[length] = '\0';
03256 ast_str_update(value);
03257 } else if (length < 0) {
03258 if (lr > -length) {
03259 char *tmp = ast_str_buffer(value);
03260 tmp[lr + length] = '\0';
03261 ast_str_update(value);
03262 } else {
03263 ast_str_reset(value);
03264 }
03265 } else {
03266
03267 ast_str_update(value);
03268 }
03269
03270 return ast_str_buffer(value);
03271 }
03272
03273
03274
03275
03276
03277
03278
03279 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
03280 {
03281 struct ast_str *str = ast_str_create(16);
03282 const char *cret;
03283
03284 cret = ast_str_retrieve_variable(&str, 0, c, headp, var);
03285 ast_copy_string(workspace, ast_str_buffer(str), workspacelen);
03286 *ret = cret ? workspace : NULL;
03287 ast_free(str);
03288 }
03289
03290 const char *ast_str_retrieve_variable(struct ast_str **str, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *var)
03291 {
03292 const char not_found = '\0';
03293 char *tmpvar;
03294 const char *ret;
03295 const char *s;
03296 int offset, length;
03297 int i, need_substring;
03298 struct varshead *places[2] = { headp, &globals };
03299 char workspace[20];
03300
03301 if (c) {
03302 ast_channel_lock(c);
03303 places[0] = ast_channel_varshead(c);
03304 }
03305
03306
03307
03308
03309
03310 tmpvar = ast_strdupa(var);
03311 need_substring = parse_variable_name(tmpvar, &offset, &length, &i );
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328 s = ¬_found;
03329 if (c) {
03330
03331 if (!strncmp(var, "CALL", 4)) {
03332 if (!strncmp(var + 4, "ING", 3)) {
03333 if (!strcmp(var + 7, "PRES")) {
03334 ast_str_set(str, maxlen, "%d",
03335 ast_party_id_presentation(&ast_channel_caller(c)->id));
03336 s = ast_str_buffer(*str);
03337 } else if (!strcmp(var + 7, "ANI2")) {
03338 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->ani2);
03339 s = ast_str_buffer(*str);
03340 } else if (!strcmp(var + 7, "TON")) {
03341 ast_str_set(str, maxlen, "%d", ast_channel_caller(c)->id.number.plan);
03342 s = ast_str_buffer(*str);
03343 } else if (!strcmp(var + 7, "TNS")) {
03344 ast_str_set(str, maxlen, "%d", ast_channel_dialed(c)->transit_network_select);
03345 s = ast_str_buffer(*str);
03346 }
03347 }
03348 } else if (!strcmp(var, "HINT")) {
03349 s = ast_str_get_hint(str, maxlen, NULL, 0, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
03350 } else if (!strcmp(var, "HINTNAME")) {
03351 s = ast_str_get_hint(NULL, 0, str, maxlen, c, ast_channel_context(c), ast_channel_exten(c)) ? ast_str_buffer(*str) : NULL;
03352 } else if (!strcmp(var, "EXTEN")) {
03353 s = ast_channel_exten(c);
03354 } else if (!strcmp(var, "CONTEXT")) {
03355 s = ast_channel_context(c);
03356 } else if (!strcmp(var, "PRIORITY")) {
03357 ast_str_set(str, maxlen, "%d", ast_channel_priority(c));
03358 s = ast_str_buffer(*str);
03359 } else if (!strcmp(var, "CHANNEL")) {
03360 s = ast_channel_name(c);
03361 } else if (!strcmp(var, "UNIQUEID")) {
03362 s = ast_channel_uniqueid(c);
03363 } else if (!strcmp(var, "HANGUPCAUSE")) {
03364 ast_str_set(str, maxlen, "%d", ast_channel_hangupcause(c));
03365 s = ast_str_buffer(*str);
03366 }
03367 }
03368 if (s == ¬_found) {
03369 if (!strcmp(var, "EPOCH")) {
03370 ast_str_set(str, maxlen, "%u", (int) time(NULL));
03371 s = ast_str_buffer(*str);
03372 } else if (!strcmp(var, "SYSTEMNAME")) {
03373 s = ast_config_AST_SYSTEM_NAME;
03374 } else if (!strcmp(var, "ASTETCDIR")) {
03375 s = ast_config_AST_CONFIG_DIR;
03376 } else if (!strcmp(var, "ASTMODDIR")) {
03377 s = ast_config_AST_MODULE_DIR;
03378 } else if (!strcmp(var, "ASTVARLIBDIR")) {
03379 s = ast_config_AST_VAR_DIR;
03380 } else if (!strcmp(var, "ASTDBDIR")) {
03381 s = ast_config_AST_DB;
03382 } else if (!strcmp(var, "ASTKEYDIR")) {
03383 s = ast_config_AST_KEY_DIR;
03384 } else if (!strcmp(var, "ASTDATADIR")) {
03385 s = ast_config_AST_DATA_DIR;
03386 } else if (!strcmp(var, "ASTAGIDIR")) {
03387 s = ast_config_AST_AGI_DIR;
03388 } else if (!strcmp(var, "ASTSPOOLDIR")) {
03389 s = ast_config_AST_SPOOL_DIR;
03390 } else if (!strcmp(var, "ASTRUNDIR")) {
03391 s = ast_config_AST_RUN_DIR;
03392 } else if (!strcmp(var, "ASTLOGDIR")) {
03393 s = ast_config_AST_LOG_DIR;
03394 } else if (!strcmp(var, "ENTITYID")) {
03395 ast_eid_to_str(workspace, sizeof(workspace), &ast_eid_default);
03396 s = workspace;
03397 }
03398 }
03399
03400 for (i = 0; s == ¬_found && i < ARRAY_LEN(places); i++) {
03401 struct ast_var_t *variables;
03402 if (!places[i])
03403 continue;
03404 if (places[i] == &globals)
03405 ast_rwlock_rdlock(&globalslock);
03406 AST_LIST_TRAVERSE(places[i], variables, entries) {
03407 if (!strcasecmp(ast_var_name(variables), var)) {
03408 s = ast_var_value(variables);
03409 break;
03410 }
03411 }
03412 if (places[i] == &globals)
03413 ast_rwlock_unlock(&globalslock);
03414 }
03415 if (s == ¬_found || s == NULL) {
03416 ast_debug(5, "Result of '%s' is NULL\n", var);
03417 ret = NULL;
03418 } else {
03419 ast_debug(5, "Result of '%s' is '%s'\n", var, s);
03420 if (s != ast_str_buffer(*str)) {
03421 ast_str_set(str, maxlen, "%s", s);
03422 }
03423 ret = ast_str_buffer(*str);
03424 if (need_substring) {
03425 ret = ast_str_substring(*str, offset, length);
03426 ast_debug(2, "Final result of '%s' is '%s'\n", var, ret);
03427 }
03428 }
03429
03430 if (c) {
03431 ast_channel_unlock(c);
03432 }
03433 return ret;
03434 }
03435
03436 static void exception_store_free(void *data)
03437 {
03438 struct pbx_exception *exception = data;
03439 ast_string_field_free_memory(exception);
03440 ast_free(exception);
03441 }
03442
03443 static const struct ast_datastore_info exception_store_info = {
03444 .type = "EXCEPTION",
03445 .destroy = exception_store_free,
03446 };
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456
03457
03458
03459 static int raise_exception(struct ast_channel *chan, const char *reason, int priority)
03460 {
03461 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03462 struct pbx_exception *exception = NULL;
03463
03464 if (!ds) {
03465 ds = ast_datastore_alloc(&exception_store_info, NULL);
03466 if (!ds)
03467 return -1;
03468 if (!(exception = ast_calloc_with_stringfields(1, struct pbx_exception, 128))) {
03469 ast_datastore_free(ds);
03470 return -1;
03471 }
03472 ds->data = exception;
03473 ast_channel_datastore_add(chan, ds);
03474 } else
03475 exception = ds->data;
03476
03477 ast_string_field_set(exception, reason, reason);
03478 ast_string_field_set(exception, context, ast_channel_context(chan));
03479 ast_string_field_set(exception, exten, ast_channel_exten(chan));
03480 exception->priority = ast_channel_priority(chan);
03481 set_ext_pri(chan, "e", priority);
03482 return 0;
03483 }
03484
03485 int pbx_builtin_raise_exception(struct ast_channel *chan, const char *reason)
03486 {
03487
03488 return raise_exception(chan, reason, 0);
03489 }
03490
03491 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
03492 {
03493 struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03494 struct pbx_exception *exception = NULL;
03495 if (!ds || !ds->data)
03496 return -1;
03497 exception = ds->data;
03498 if (!strcasecmp(data, "REASON"))
03499 ast_copy_string(buf, exception->reason, buflen);
03500 else if (!strcasecmp(data, "CONTEXT"))
03501 ast_copy_string(buf, exception->context, buflen);
03502 else if (!strncasecmp(data, "EXTEN", 5))
03503 ast_copy_string(buf, exception->exten, buflen);
03504 else if (!strcasecmp(data, "PRIORITY"))
03505 snprintf(buf, buflen, "%d", exception->priority);
03506 else
03507 return -1;
03508 return 0;
03509 }
03510
03511 static struct ast_custom_function exception_function = {
03512 .name = "EXCEPTION",
03513 .read = acf_exception_read,
03514 };
03515
03516 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03517 {
03518 struct ast_custom_function *acf;
03519 int count_acf = 0;
03520 int like = 0;
03521
03522 switch (cmd) {
03523 case CLI_INIT:
03524 e->command = "core show functions [like]";
03525 e->usage =
03526 "Usage: core show functions [like <text>]\n"
03527 " List builtin functions, optionally only those matching a given string\n";
03528 return NULL;
03529 case CLI_GENERATE:
03530 return NULL;
03531 }
03532
03533 if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
03534 like = 1;
03535 } else if (a->argc != 3) {
03536 return CLI_SHOWUSAGE;
03537 }
03538
03539 ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
03540
03541 AST_RWLIST_RDLOCK(&acf_root);
03542 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03543 if (!like || strstr(acf->name, a->argv[4])) {
03544 count_acf++;
03545 ast_cli(a->fd, "%-20.20s %-35.35s %s\n",
03546 S_OR(acf->name, ""),
03547 S_OR(acf->syntax, ""),
03548 S_OR(acf->synopsis, ""));
03549 }
03550 }
03551 AST_RWLIST_UNLOCK(&acf_root);
03552
03553 ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
03554
03555 return CLI_SUCCESS;
03556 }
03557
03558 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03559 {
03560 struct ast_custom_function *acf;
03561
03562 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
03563 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
03564 char stxtitle[40], *syntax = NULL, *arguments = NULL;
03565 int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
03566 char *ret = NULL;
03567 int which = 0;
03568 int wordlen;
03569
03570 switch (cmd) {
03571 case CLI_INIT:
03572 e->command = "core show function";
03573 e->usage =
03574 "Usage: core show function <function>\n"
03575 " Describe a particular dialplan function.\n";
03576 return NULL;
03577 case CLI_GENERATE:
03578 wordlen = strlen(a->word);
03579
03580 AST_RWLIST_RDLOCK(&acf_root);
03581 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03582 if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
03583 ret = ast_strdup(acf->name);
03584 break;
03585 }
03586 }
03587 AST_RWLIST_UNLOCK(&acf_root);
03588
03589 return ret;
03590 }
03591
03592 if (a->argc < 4) {
03593 return CLI_SHOWUSAGE;
03594 }
03595
03596 if (!(acf = ast_custom_function_find(a->argv[3]))) {
03597 ast_cli(a->fd, "No function by that name registered.\n");
03598 return CLI_FAILURE;
03599 }
03600
03601 syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03602 if (!(syntax = ast_malloc(syntax_size))) {
03603 ast_cli(a->fd, "Memory allocation failure!\n");
03604 return CLI_FAILURE;
03605 }
03606
03607 snprintf(info, sizeof(info), "\n -= Info about function '%s' =- \n\n", acf->name);
03608 term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
03609 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03610 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03611 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
03612 term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
03613 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
03614 term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
03615 #ifdef AST_XML_DOCS
03616 if (acf->docsrc == AST_XML_DOC) {
03617 arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
03618 synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
03619 description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
03620 seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
03621 } else
03622 #endif
03623 {
03624 synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03625 synopsis = ast_malloc(synopsis_size);
03626
03627 description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03628 description = ast_malloc(description_size);
03629
03630 arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03631 arguments = ast_malloc(arguments_size);
03632
03633 seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03634 seealso = ast_malloc(seealso_size);
03635
03636
03637 if (!synopsis || !description || !arguments || !seealso) {
03638 ast_free(synopsis);
03639 ast_free(description);
03640 ast_free(arguments);
03641 ast_free(seealso);
03642 ast_free(syntax);
03643 return CLI_FAILURE;
03644 }
03645
03646 term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
03647 term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
03648 term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
03649 term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
03650 }
03651
03652 ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
03653 infotitle, syntitle, synopsis, destitle, description,
03654 stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
03655
03656 ast_free(arguments);
03657 ast_free(synopsis);
03658 ast_free(description);
03659 ast_free(seealso);
03660 ast_free(syntax);
03661
03662 return CLI_SUCCESS;
03663 }
03664
03665 struct ast_custom_function *ast_custom_function_find(const char *name)
03666 {
03667 struct ast_custom_function *acf = NULL;
03668
03669 AST_RWLIST_RDLOCK(&acf_root);
03670 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03671 if (!strcmp(name, acf->name))
03672 break;
03673 }
03674 AST_RWLIST_UNLOCK(&acf_root);
03675
03676 return acf;
03677 }
03678
03679 int ast_custom_function_unregister(struct ast_custom_function *acf)
03680 {
03681 struct ast_custom_function *cur;
03682
03683 if (!acf) {
03684 return -1;
03685 }
03686
03687 AST_RWLIST_WRLOCK(&acf_root);
03688 if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
03689 #ifdef AST_XML_DOCS
03690 if (cur->docsrc == AST_XML_DOC) {
03691 ast_string_field_free_memory(acf);
03692 }
03693 #endif
03694 ast_verb(2, "Unregistered custom function %s\n", cur->name);
03695 }
03696 AST_RWLIST_UNLOCK(&acf_root);
03697
03698 return cur ? 0 : -1;
03699 }
03700
03701
03702
03703
03704
03705
03706
03707
03708
03709 static int acf_retrieve_docs(struct ast_custom_function *acf)
03710 {
03711 #ifdef AST_XML_DOCS
03712 char *tmpxml;
03713
03714
03715 if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
03716 return 0;
03717 }
03718
03719 if (ast_string_field_init(acf, 128)) {
03720 return -1;
03721 }
03722
03723
03724 tmpxml = ast_xmldoc_build_synopsis("function", acf->name, ast_module_name(acf->mod));
03725 ast_string_field_set(acf, synopsis, tmpxml);
03726 ast_free(tmpxml);
03727
03728
03729 tmpxml = ast_xmldoc_build_description("function", acf->name, ast_module_name(acf->mod));
03730 ast_string_field_set(acf, desc, tmpxml);
03731 ast_free(tmpxml);
03732
03733
03734 tmpxml = ast_xmldoc_build_syntax("function", acf->name, ast_module_name(acf->mod));
03735 ast_string_field_set(acf, syntax, tmpxml);
03736 ast_free(tmpxml);
03737
03738
03739 tmpxml = ast_xmldoc_build_arguments("function", acf->name, ast_module_name(acf->mod));
03740 ast_string_field_set(acf, arguments, tmpxml);
03741 ast_free(tmpxml);
03742
03743
03744 tmpxml = ast_xmldoc_build_seealso("function", acf->name, ast_module_name(acf->mod));
03745 ast_string_field_set(acf, seealso, tmpxml);
03746 ast_free(tmpxml);
03747
03748 acf->docsrc = AST_XML_DOC;
03749 #endif
03750
03751 return 0;
03752 }
03753
03754 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
03755 {
03756 struct ast_custom_function *cur;
03757 char tmps[80];
03758
03759 if (!acf) {
03760 return -1;
03761 }
03762
03763 acf->mod = mod;
03764 #ifdef AST_XML_DOCS
03765 acf->docsrc = AST_STATIC_DOC;
03766 #endif
03767
03768 if (acf_retrieve_docs(acf)) {
03769 return -1;
03770 }
03771
03772 AST_RWLIST_WRLOCK(&acf_root);
03773
03774 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
03775 if (!strcmp(acf->name, cur->name)) {
03776 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
03777 AST_RWLIST_UNLOCK(&acf_root);
03778 return -1;
03779 }
03780 }
03781
03782
03783 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
03784 if (strcasecmp(acf->name, cur->name) < 0) {
03785 AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
03786 break;
03787 }
03788 }
03789 AST_RWLIST_TRAVERSE_SAFE_END;
03790
03791 if (!cur) {
03792 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
03793 }
03794
03795 AST_RWLIST_UNLOCK(&acf_root);
03796
03797 ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
03798
03799 return 0;
03800 }
03801
03802
03803
03804
03805 static char *func_args(char *function)
03806 {
03807 char *args = strchr(function, '(');
03808
03809 if (!args) {
03810 ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
03811 } else {
03812 char *p;
03813 *args++ = '\0';
03814 if ((p = strrchr(args, ')'))) {
03815 *p = '\0';
03816 } else {
03817 ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
03818 }
03819 }
03820 return args;
03821 }
03822
03823 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
03824 {
03825 char *copy = ast_strdupa(function);
03826 char *args = func_args(copy);
03827 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03828 int res;
03829 struct ast_module_user *u = NULL;
03830
03831 if (acfptr == NULL) {
03832 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03833 } else if (!acfptr->read && !acfptr->read2) {
03834 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
03835 } else if (acfptr->read) {
03836 if (acfptr->mod) {
03837 u = __ast_module_user_add(acfptr->mod, chan);
03838 }
03839 res = acfptr->read(chan, copy, args, workspace, len);
03840 if (acfptr->mod && u) {
03841 __ast_module_user_remove(acfptr->mod, u);
03842 }
03843 return res;
03844 } else {
03845 struct ast_str *str = ast_str_create(16);
03846 if (acfptr->mod) {
03847 u = __ast_module_user_add(acfptr->mod, chan);
03848 }
03849 res = acfptr->read2(chan, copy, args, &str, 0);
03850 if (acfptr->mod && u) {
03851 __ast_module_user_remove(acfptr->mod, u);
03852 }
03853 ast_copy_string(workspace, ast_str_buffer(str), len > ast_str_size(str) ? ast_str_size(str) : len);
03854 ast_free(str);
03855 return res;
03856 }
03857 return -1;
03858 }
03859
03860 int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen)
03861 {
03862 char *copy = ast_strdupa(function);
03863 char *args = func_args(copy);
03864 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03865 int res;
03866 struct ast_module_user *u = NULL;
03867
03868 if (acfptr == NULL) {
03869 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03870 } else if (!acfptr->read && !acfptr->read2) {
03871 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
03872 } else {
03873 if (acfptr->mod) {
03874 u = __ast_module_user_add(acfptr->mod, chan);
03875 }
03876 ast_str_reset(*str);
03877 if (acfptr->read2) {
03878
03879 res = acfptr->read2(chan, copy, args, str, maxlen);
03880 } else {
03881
03882 int maxsize = ast_str_size(*str);
03883 if (maxlen > -1) {
03884 if (maxlen == 0) {
03885 if (acfptr->read_max) {
03886 maxsize = acfptr->read_max;
03887 } else {
03888 maxsize = VAR_BUF_SIZE;
03889 }
03890 } else {
03891 maxsize = maxlen;
03892 }
03893 ast_str_make_space(str, maxsize);
03894 }
03895 res = acfptr->read(chan, copy, args, ast_str_buffer(*str), maxsize);
03896 }
03897 if (acfptr->mod && u) {
03898 __ast_module_user_remove(acfptr->mod, u);
03899 }
03900 return res;
03901 }
03902 return -1;
03903 }
03904
03905 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
03906 {
03907 char *copy = ast_strdupa(function);
03908 char *args = func_args(copy);
03909 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03910
03911 if (acfptr == NULL)
03912 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03913 else if (!acfptr->write)
03914 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
03915 else {
03916 int res;
03917 struct ast_module_user *u = NULL;
03918 if (acfptr->mod)
03919 u = __ast_module_user_add(acfptr->mod, chan);
03920 res = acfptr->write(chan, copy, args, value);
03921 if (acfptr->mod && u)
03922 __ast_module_user_remove(acfptr->mod, u);
03923 return res;
03924 }
03925
03926 return -1;
03927 }
03928
03929 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)
03930 {
03931
03932 char *cp4 = NULL;
03933 const char *whereweare;
03934 int orig_size = 0;
03935 int offset, offset2, isfunction;
03936 const char *nextvar, *nextexp, *nextthing;
03937 const char *vars, *vare;
03938 char *finalvars;
03939 int pos, brackets, needsub, len;
03940 struct ast_str *substr1 = ast_str_create(16), *substr2 = NULL, *substr3 = ast_str_create(16);
03941
03942 ast_str_reset(*buf);
03943 whereweare = templ;
03944 while (!ast_strlen_zero(whereweare)) {
03945
03946 ast_str_reset(substr3);
03947
03948
03949 pos = strlen(whereweare);
03950 nextvar = NULL;
03951 nextexp = NULL;
03952 nextthing = strchr(whereweare, '$');
03953 if (nextthing) {
03954 switch (nextthing[1]) {
03955 case '{':
03956 nextvar = nextthing;
03957 pos = nextvar - whereweare;
03958 break;
03959 case '[':
03960 nextexp = nextthing;
03961 pos = nextexp - whereweare;
03962 break;
03963 default:
03964 pos = 1;
03965 }
03966 }
03967
03968 if (pos) {
03969
03970 ast_str_append_substr(buf, maxlen, whereweare, pos);
03971
03972 templ += pos;
03973 whereweare += pos;
03974 }
03975
03976 if (nextvar) {
03977
03978
03979
03980 vars = vare = nextvar + 2;
03981 brackets = 1;
03982 needsub = 0;
03983
03984
03985 while (brackets && *vare) {
03986 if ((vare[0] == '$') && (vare[1] == '{')) {
03987 needsub++;
03988 } else if (vare[0] == '{') {
03989 brackets++;
03990 } else if (vare[0] == '}') {
03991 brackets--;
03992 } else if ((vare[0] == '$') && (vare[1] == '['))
03993 needsub++;
03994 vare++;
03995 }
03996 if (brackets)
03997 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
03998 len = vare - vars - 1;
03999
04000
04001 whereweare += (len + 3);
04002
04003
04004 ast_str_set_substr(&substr1, 0, vars, len);
04005 ast_debug(5, "Evaluating '%s' (from '%s' len %d)\n", ast_str_buffer(substr1), vars, len);
04006
04007
04008 if (needsub) {
04009 size_t used;
04010 if (!substr2) {
04011 substr2 = ast_str_create(16);
04012 }
04013
04014 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
04015 finalvars = ast_str_buffer(substr2);
04016 } else {
04017 finalvars = ast_str_buffer(substr1);
04018 }
04019
04020 parse_variable_name(finalvars, &offset, &offset2, &isfunction);
04021 if (isfunction) {
04022
04023 if (c || !headp) {
04024 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
04025 } else {
04026 struct varshead old;
04027 struct ast_channel *bogus = ast_dummy_channel_alloc();
04028 if (bogus) {
04029 memcpy(&old, ast_channel_varshead(bogus), sizeof(old));
04030 memcpy(ast_channel_varshead(bogus), headp, sizeof(*ast_channel_varshead(bogus)));
04031 cp4 = ast_func_read2(c, finalvars, &substr3, 0) ? NULL : ast_str_buffer(substr3);
04032
04033 memcpy(ast_channel_varshead(bogus), &old, sizeof(*ast_channel_varshead(bogus)));
04034 ast_channel_unref(bogus);
04035 } else {
04036 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
04037 }
04038 }
04039 ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
04040 } else {
04041
04042 ast_str_retrieve_variable(&substr3, 0, c, headp, finalvars);
04043 cp4 = ast_str_buffer(substr3);
04044 }
04045 if (cp4) {
04046 ast_str_substring(substr3, offset, offset2);
04047 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
04048 }
04049 } else if (nextexp) {
04050
04051
04052
04053 vars = vare = nextexp + 2;
04054 brackets = 1;
04055 needsub = 0;
04056
04057
04058 while (brackets && *vare) {
04059 if ((vare[0] == '$') && (vare[1] == '[')) {
04060 needsub++;
04061 brackets++;
04062 vare++;
04063 } else if (vare[0] == '[') {
04064 brackets++;
04065 } else if (vare[0] == ']') {
04066 brackets--;
04067 } else if ((vare[0] == '$') && (vare[1] == '{')) {
04068 needsub++;
04069 vare++;
04070 }
04071 vare++;
04072 }
04073 if (brackets)
04074 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
04075 len = vare - vars - 1;
04076
04077
04078 whereweare += (len + 3);
04079
04080
04081 ast_str_set_substr(&substr1, 0, vars, len);
04082
04083
04084 if (needsub) {
04085 size_t used;
04086 if (!substr2) {
04087 substr2 = ast_str_create(16);
04088 }
04089
04090 ast_str_substitute_variables_full(&substr2, 0, c, headp, ast_str_buffer(substr1), &used);
04091 finalvars = ast_str_buffer(substr2);
04092 } else {
04093 finalvars = ast_str_buffer(substr1);
04094 }
04095
04096 if (ast_str_expr(&substr3, 0, c, finalvars)) {
04097 ast_debug(2, "Expression result is '%s'\n", ast_str_buffer(substr3));
04098 }
04099 ast_str_append(buf, maxlen, "%s", ast_str_buffer(substr3));
04100 }
04101 }
04102 *used = ast_str_strlen(*buf) - orig_size;
04103 ast_free(substr1);
04104 ast_free(substr2);
04105 ast_free(substr3);
04106 }
04107
04108 void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
04109 {
04110 size_t used;
04111 ast_str_substitute_variables_full(buf, maxlen, chan, NULL, templ, &used);
04112 }
04113
04114 void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ)
04115 {
04116 size_t used;
04117 ast_str_substitute_variables_full(buf, maxlen, NULL, headp, templ, &used);
04118 }
04119
04120 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
04121 {
04122
04123 char *cp4 = NULL;
04124 const char *whereweare, *orig_cp2 = cp2;
04125 int length, offset, offset2, isfunction;
04126 char *workspace = NULL;
04127 char *ltmp = NULL, *var = NULL;
04128 char *nextvar, *nextexp, *nextthing;
04129 char *vars, *vare;
04130 int pos, brackets, needsub, len;
04131
04132 *cp2 = 0;
04133 whereweare = cp1;
04134 while (!ast_strlen_zero(whereweare) && count) {
04135
04136 pos = strlen(whereweare);
04137 nextvar = NULL;
04138 nextexp = NULL;
04139 nextthing = strchr(whereweare, '$');
04140 if (nextthing) {
04141 switch (nextthing[1]) {
04142 case '{':
04143 nextvar = nextthing;
04144 pos = nextvar - whereweare;
04145 break;
04146 case '[':
04147 nextexp = nextthing;
04148 pos = nextexp - whereweare;
04149 break;
04150 default:
04151 pos = 1;
04152 }
04153 }
04154
04155 if (pos) {
04156
04157 if (pos > count)
04158 pos = count;
04159
04160
04161 memcpy(cp2, whereweare, pos);
04162
04163 count -= pos;
04164 cp2 += pos;
04165 whereweare += pos;
04166 *cp2 = 0;
04167 }
04168
04169 if (nextvar) {
04170
04171
04172
04173 vars = vare = nextvar + 2;
04174 brackets = 1;
04175 needsub = 0;
04176
04177
04178 while (brackets && *vare) {
04179 if ((vare[0] == '$') && (vare[1] == '{')) {
04180 needsub++;
04181 } else if (vare[0] == '{') {
04182 brackets++;
04183 } else if (vare[0] == '}') {
04184 brackets--;
04185 } else if ((vare[0] == '$') && (vare[1] == '['))
04186 needsub++;
04187 vare++;
04188 }
04189 if (brackets)
04190 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
04191 len = vare - vars - 1;
04192
04193
04194 whereweare += (len + 3);
04195
04196 if (!var)
04197 var = ast_alloca(VAR_BUF_SIZE);
04198
04199
04200 ast_copy_string(var, vars, len + 1);
04201
04202
04203 if (needsub) {
04204 size_t used;
04205 if (!ltmp)
04206 ltmp = ast_alloca(VAR_BUF_SIZE);
04207
04208 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
04209 vars = ltmp;
04210 } else {
04211 vars = var;
04212 }
04213
04214 if (!workspace)
04215 workspace = ast_alloca(VAR_BUF_SIZE);
04216
04217 workspace[0] = '\0';
04218
04219 parse_variable_name(vars, &offset, &offset2, &isfunction);
04220 if (isfunction) {
04221
04222 if (c || !headp)
04223 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
04224 else {
04225 struct varshead old;
04226 struct ast_channel *c = ast_dummy_channel_alloc();
04227 if (c) {
04228 memcpy(&old, ast_channel_varshead(c), sizeof(old));
04229 memcpy(ast_channel_varshead(c), headp, sizeof(*ast_channel_varshead(c)));
04230 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
04231
04232 memcpy(ast_channel_varshead(c), &old, sizeof(*ast_channel_varshead(c)));
04233 c = ast_channel_unref(c);
04234 } else {
04235 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
04236 }
04237 }
04238 ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
04239 } else {
04240
04241 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
04242 }
04243 if (cp4) {
04244 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
04245
04246 length = strlen(cp4);
04247 if (length > count)
04248 length = count;
04249 memcpy(cp2, cp4, length);
04250 count -= length;
04251 cp2 += length;
04252 *cp2 = 0;
04253 }
04254 } else if (nextexp) {
04255
04256
04257
04258 vars = vare = nextexp + 2;
04259 brackets = 1;
04260 needsub = 0;
04261
04262
04263 while (brackets && *vare) {
04264 if ((vare[0] == '$') && (vare[1] == '[')) {
04265 needsub++;
04266 brackets++;
04267 vare++;
04268 } else if (vare[0] == '[') {
04269 brackets++;
04270 } else if (vare[0] == ']') {
04271 brackets--;
04272 } else if ((vare[0] == '$') && (vare[1] == '{')) {
04273 needsub++;
04274 vare++;
04275 }
04276 vare++;
04277 }
04278 if (brackets)
04279 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
04280 len = vare - vars - 1;
04281
04282
04283 whereweare += (len + 3);
04284
04285 if (!var)
04286 var = ast_alloca(VAR_BUF_SIZE);
04287
04288
04289 ast_copy_string(var, vars, len + 1);
04290
04291
04292 if (needsub) {
04293 size_t used;
04294 if (!ltmp)
04295 ltmp = ast_alloca(VAR_BUF_SIZE);
04296
04297 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
04298 vars = ltmp;
04299 } else {
04300 vars = var;
04301 }
04302
04303 length = ast_expr(vars, cp2, count, c);
04304
04305 if (length) {
04306 ast_debug(1, "Expression result is '%s'\n", cp2);
04307 count -= length;
04308 cp2 += length;
04309 *cp2 = 0;
04310 }
04311 }
04312 }
04313 *used = cp2 - orig_cp2;
04314 }
04315
04316 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
04317 {
04318 size_t used;
04319 pbx_substitute_variables_helper_full(c, (c) ? ast_channel_varshead(c) : NULL, cp1, cp2, count, &used);
04320 }
04321
04322 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
04323 {
04324 size_t used;
04325 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
04326 }
04327
04328 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
04329 {
04330 const char *tmp;
04331
04332
04333 if (!e->data) {
04334 *passdata = '\0';
04335 return;
04336 }
04337
04338
04339 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
04340 ast_copy_string(passdata, e->data, datalen);
04341 return;
04342 }
04343
04344 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
04345 }
04346
04347
04348
04349
04350
04351
04352
04353
04354
04355
04356
04357
04358
04359
04360
04361
04362
04363
04364
04365 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
04366 const char *context, const char *exten, int priority,
04367 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
04368 {
04369 struct ast_exten *e;
04370 struct ast_app *app;
04371 int res;
04372 struct pbx_find_info q = { .stacklen = 0 };
04373 char passdata[EXT_DATA_SIZE];
04374
04375 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
04376
04377 ast_rdlock_contexts();
04378 if (found)
04379 *found = 0;
04380
04381 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
04382 if (e) {
04383 if (found)
04384 *found = 1;
04385 if (matching_action) {
04386 ast_unlock_contexts();
04387 return -1;
04388 } else if (action == E_FINDLABEL) {
04389 res = e->priority;
04390 ast_unlock_contexts();
04391 return res;
04392 } else {
04393 if (!e->cached_app)
04394 e->cached_app = pbx_findapp(e->app);
04395 app = e->cached_app;
04396 ast_unlock_contexts();
04397 if (!app) {
04398 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
04399 return -1;
04400 }
04401 if (ast_channel_context(c) != context)
04402 ast_channel_context_set(c, context);
04403 if (ast_channel_exten(c) != exten)
04404 ast_channel_exten_set(c, exten);
04405 ast_channel_priority_set(c, priority);
04406 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
04407 #ifdef CHANNEL_TRACE
04408 ast_channel_trace_update(c);
04409 #endif
04410 ast_debug(1, "Launching '%s'\n", app->name);
04411 {
04412 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
04413 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
04414 exten, context, priority,
04415 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
04416 term_color(tmp2, ast_channel_name(c), COLOR_BRMAGENTA, 0, sizeof(tmp2)),
04417 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
04418 "in new stack");
04419 }
04420
04421
04422
04423
04424
04425
04426
04427
04428
04429
04430
04431
04432
04433 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
04434 "Channel: %s\r\n"
04435 "Context: %s\r\n"
04436 "Extension: %s\r\n"
04437 "Priority: %d\r\n"
04438 "Application: %s\r\n"
04439 "AppData: %s\r\n"
04440 "Uniqueid: %s\r\n",
04441 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c), app->name, passdata, ast_channel_uniqueid(c));
04442 return pbx_exec(c, app, passdata);
04443 }
04444 } else if (q.swo) {
04445 if (found)
04446 *found = 1;
04447 ast_unlock_contexts();
04448 if (matching_action) {
04449 return -1;
04450 } else {
04451 if (!q.swo->exec) {
04452 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
04453 res = -1;
04454 }
04455 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
04456 }
04457 } else {
04458 ast_unlock_contexts();
04459
04460 switch (q.status) {
04461 case STATUS_NO_CONTEXT:
04462 if (!matching_action && !combined_find_spawn)
04463 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
04464 break;
04465 case STATUS_NO_EXTENSION:
04466 if (!matching_action && !combined_find_spawn)
04467 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
04468 break;
04469 case STATUS_NO_PRIORITY:
04470 if (!matching_action && !combined_find_spawn)
04471 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
04472 break;
04473 case STATUS_NO_LABEL:
04474 if (context && !combined_find_spawn)
04475 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
04476 break;
04477 default:
04478 ast_debug(1, "Shouldn't happen!\n");
04479 }
04480
04481 return (matching_action) ? 0 : -1;
04482 }
04483 }
04484
04485
04486 static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
04487 {
04488 struct pbx_find_info q = { .stacklen = 0 };
04489 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
04490 }
04491
04492 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
04493 {
04494 struct ast_exten *e;
04495 ast_rdlock_contexts();
04496 e = ast_hint_extension_nolock(c, context, exten);
04497 ast_unlock_contexts();
04498 return e;
04499 }
04500
04501 enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
04502 {
04503 switch (devstate) {
04504 case AST_DEVICE_ONHOLD:
04505 return AST_EXTENSION_ONHOLD;
04506 case AST_DEVICE_BUSY:
04507 return AST_EXTENSION_BUSY;
04508 case AST_DEVICE_UNKNOWN:
04509 return AST_EXTENSION_NOT_INUSE;
04510 case AST_DEVICE_UNAVAILABLE:
04511 case AST_DEVICE_INVALID:
04512 return AST_EXTENSION_UNAVAILABLE;
04513 case AST_DEVICE_RINGINUSE:
04514 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
04515 case AST_DEVICE_RINGING:
04516 return AST_EXTENSION_RINGING;
04517 case AST_DEVICE_INUSE:
04518 return AST_EXTENSION_INUSE;
04519 case AST_DEVICE_NOT_INUSE:
04520 return AST_EXTENSION_NOT_INUSE;
04521 case AST_DEVICE_TOTAL:
04522 break;
04523 }
04524
04525 return AST_EXTENSION_NOT_INUSE;
04526 }
04527
04528
04529
04530
04531
04532 static char *parse_hint_presence(struct ast_str *hint_args)
04533 {
04534 char *copy = ast_strdupa(ast_str_buffer(hint_args));
04535 char *tmp = "";
04536
04537 if ((tmp = strrchr(copy, ','))) {
04538 *tmp = '\0';
04539 tmp++;
04540 } else {
04541 return NULL;
04542 }
04543 ast_str_set(&hint_args, 0, "%s", tmp);
04544 return ast_str_buffer(hint_args);
04545 }
04546
04547
04548
04549
04550
04551 static char *parse_hint_device(struct ast_str *hint_args)
04552 {
04553 char *copy = ast_strdupa(ast_str_buffer(hint_args));
04554 char *tmp;
04555
04556 if ((tmp = strrchr(copy, ','))) {
04557 *tmp = '\0';
04558 }
04559
04560 ast_str_set(&hint_args, 0, "%s", copy);
04561 return ast_str_buffer(hint_args);
04562 }
04563
04564 static void device_state_info_dt(void *obj)
04565 {
04566 struct ast_device_state_info *info = obj;
04567
04568 ao2_cleanup(info->causing_channel);
04569 }
04570
04571 static struct ao2_container *alloc_device_state_info(void)
04572 {
04573 return ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
04574 }
04575
04576 static int ast_extension_state3(struct ast_str *hint_app, struct ao2_container *device_state_info)
04577 {
04578 char *cur;
04579 char *rest;
04580 struct ast_devstate_aggregate agg;
04581
04582
04583 rest = parse_hint_device(hint_app);
04584
04585 ast_devstate_aggregate_init(&agg);
04586 while ((cur = strsep(&rest, "&"))) {
04587 enum ast_device_state state = ast_device_state(cur);
04588
04589 ast_devstate_aggregate_add(&agg, state);
04590 if (device_state_info) {
04591 struct ast_device_state_info *obj;
04592
04593 obj = ao2_alloc_options(sizeof(*obj) + strlen(cur), device_state_info_dt, AO2_ALLOC_OPT_LOCK_NOLOCK);
04594
04595 if (obj) {
04596 obj->device_state = state;
04597 strcpy(obj->device_name, cur);
04598 ao2_link(device_state_info, obj);
04599 ao2_ref(obj, -1);
04600 }
04601 }
04602 }
04603
04604 return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
04605 }
04606
04607
04608 static int ast_extension_state2(struct ast_exten *e, struct ao2_container *device_state_info)
04609 {
04610 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
04611
04612 if (!e || !hint_app) {
04613 return -1;
04614 }
04615
04616 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(e));
04617 return ast_extension_state3(hint_app, device_state_info);
04618 }
04619
04620
04621 const char *ast_extension_state2str(int extension_state)
04622 {
04623 int i;
04624
04625 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
04626 if (extension_states[i].extension_state == extension_state)
04627 return extension_states[i].text;
04628 }
04629 return "Unknown";
04630 }
04631
04632
04633 static int internal_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
04634 struct ao2_container *device_state_info)
04635 {
04636 struct ast_exten *e;
04637
04638 if (!(e = ast_hint_extension(c, context, exten))) {
04639 return -1;
04640 }
04641
04642 if (e->exten[0] == '_') {
04643
04644 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
04645 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
04646 e->registrar);
04647 if (!(e = ast_hint_extension(c, context, exten))) {
04648
04649 return -1;
04650 }
04651 }
04652
04653 return ast_extension_state2(e, device_state_info);
04654 }
04655
04656
04657 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
04658 {
04659 return internal_extension_state_extended(c, context, exten, NULL);
04660 }
04661
04662
04663 int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
04664 struct ao2_container **device_state_info)
04665 {
04666 struct ao2_container *container = NULL;
04667 int ret;
04668
04669 if (device_state_info) {
04670 container = alloc_device_state_info();
04671 }
04672
04673 ret = internal_extension_state_extended(c, context, exten, container);
04674 if (ret < 0 && container) {
04675 ao2_ref(container, -1);
04676 container = NULL;
04677 }
04678
04679 if (device_state_info) {
04680 get_device_state_causing_channels(container);
04681 *device_state_info = container;
04682 }
04683
04684 return ret;
04685 }
04686
04687 static int extension_presence_state_helper(struct ast_exten *e, char **subtype, char **message)
04688 {
04689 struct ast_str *hint_app = ast_str_thread_get(&extensionstate_buf, 32);
04690 char *presence_provider;
04691 const char *app;
04692
04693 if (!e || !hint_app) {
04694 return -1;
04695 }
04696
04697 app = ast_get_extension_app(e);
04698 if (ast_strlen_zero(app)) {
04699 return -1;
04700 }
04701
04702 ast_str_set(&hint_app, 0, "%s", app);
04703 presence_provider = parse_hint_presence(hint_app);
04704
04705 if (ast_strlen_zero(presence_provider)) {
04706
04707 return 0;
04708 }
04709
04710 return ast_presence_state(presence_provider, subtype, message);
04711 }
04712
04713 int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
04714 {
04715 struct ast_exten *e;
04716
04717 if (!(e = ast_hint_extension(c, context, exten))) {
04718 return -1;
04719 }
04720
04721 if (e->exten[0] == '_') {
04722
04723 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
04724 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
04725 e->registrar);
04726 if (!(e = ast_hint_extension(c, context, exten))) {
04727
04728 return -1;
04729 }
04730 }
04731
04732 return extension_presence_state_helper(e, subtype, message);
04733 }
04734
04735 static int execute_state_callback(ast_state_cb_type cb,
04736 const char *context,
04737 const char *exten,
04738 void *data,
04739 enum ast_state_cb_update_reason reason,
04740 struct ast_hint *hint,
04741 struct ao2_container *device_state_info)
04742 {
04743 int res = 0;
04744 struct ast_state_cb_info info = { 0, };
04745
04746 info.reason = reason;
04747
04748
04749 if (hint) {
04750 ao2_lock(hint);
04751 info.exten_state = hint->laststate;
04752 info.device_state_info = device_state_info;
04753 info.presence_state = hint->last_presence_state;
04754 if (!(ast_strlen_zero(hint->last_presence_subtype))) {
04755 info.presence_subtype = ast_strdupa(hint->last_presence_subtype);
04756 } else {
04757 info.presence_subtype = "";
04758 }
04759 if (!(ast_strlen_zero(hint->last_presence_message))) {
04760 info.presence_message = ast_strdupa(hint->last_presence_message);
04761 } else {
04762 info.presence_message = "";
04763 }
04764 ao2_unlock(hint);
04765 } else {
04766 info.exten_state = AST_EXTENSION_REMOVED;
04767 }
04768
04769
04770 res = cb((char *) context, (char *) exten, &info, data);
04771
04772 return res;
04773 }
04774
04775 static int handle_presencechange(void *datap)
04776 {
04777 struct ast_hint *hint;
04778 struct ast_str *hint_app = NULL;
04779 struct presencechange *pc = datap;
04780 struct ao2_iterator i;
04781 struct ao2_iterator cb_iter;
04782 char context_name[AST_MAX_CONTEXT];
04783 char exten_name[AST_MAX_EXTENSION];
04784 int res = -1;
04785
04786 hint_app = ast_str_create(1024);
04787 if (!hint_app) {
04788 goto presencechange_cleanup;
04789 }
04790
04791 ast_mutex_lock(&context_merge_lock);
04792 i = ao2_iterator_init(hints, 0);
04793 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
04794 struct ast_state_cb *state_cb;
04795 const char *app;
04796 char *parse;
04797
04798 ao2_lock(hint);
04799
04800 if (!hint->exten) {
04801
04802 ao2_unlock(hint);
04803 continue;
04804 }
04805
04806
04807 app = ast_get_extension_app(hint->exten);
04808 if (ast_strlen_zero(app)) {
04809
04810 ao2_unlock(hint);
04811 continue;
04812 }
04813
04814 ast_str_set(&hint_app, 0, "%s", app);
04815 parse = parse_hint_presence(hint_app);
04816 if (ast_strlen_zero(parse)) {
04817 ao2_unlock(hint);
04818 continue;
04819 }
04820 if (strcasecmp(parse, pc->provider)) {
04821
04822 ao2_unlock(hint);
04823 continue;
04824 }
04825
04826
04827
04828
04829
04830 ast_copy_string(context_name,
04831 ast_get_context_name(ast_get_extension_context(hint->exten)),
04832 sizeof(context_name));
04833 ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
04834 sizeof(exten_name));
04835 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
04836
04837
04838 if ((hint->last_presence_state == pc->state) &&
04839 ((hint->last_presence_subtype && pc->subtype && !strcmp(hint->last_presence_subtype, pc->subtype)) || (!hint->last_presence_subtype && !pc->subtype)) &&
04840 ((hint->last_presence_message && pc->message && !strcmp(hint->last_presence_message, pc->message)) || (!hint->last_presence_message && !pc->message))) {
04841
04842
04843 ao2_unlock(hint);
04844 continue;
04845 }
04846
04847
04848 ast_free(hint->last_presence_subtype);
04849 ast_free(hint->last_presence_message);
04850 hint->last_presence_state = pc->state;
04851 hint->last_presence_subtype = pc->subtype ? ast_strdup(pc->subtype) : NULL;
04852 hint->last_presence_message = pc->message ? ast_strdup(pc->message) : NULL;
04853
04854 ao2_unlock(hint);
04855
04856
04857 cb_iter = ao2_iterator_init(statecbs, 0);
04858 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
04859 execute_state_callback(state_cb->change_cb,
04860 context_name,
04861 exten_name,
04862 state_cb->data,
04863 AST_HINT_UPDATE_PRESENCE,
04864 hint,
04865 NULL);
04866 }
04867 ao2_iterator_destroy(&cb_iter);
04868
04869
04870 cb_iter = ao2_iterator_init(hint->callbacks, 0);
04871 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
04872 execute_state_callback(state_cb->change_cb,
04873 context_name,
04874 exten_name,
04875 state_cb->data,
04876 AST_HINT_UPDATE_PRESENCE,
04877 hint,
04878 NULL);
04879 }
04880 ao2_iterator_destroy(&cb_iter);
04881 }
04882 ao2_iterator_destroy(&i);
04883 ast_mutex_unlock(&context_merge_lock);
04884
04885 res = 0;
04886
04887 presencechange_cleanup:
04888 ast_free(hint_app);
04889 ao2_ref(pc, -1);
04890
04891 return res;
04892 }
04893
04894
04895
04896
04897
04898
04899
04900
04901 static void get_device_state_causing_channels(struct ao2_container *c)
04902 {
04903 struct ao2_iterator iter;
04904 struct ast_device_state_info *info;
04905 struct ast_channel *chan;
04906
04907 if (!c || !ao2_container_count(c)) {
04908 return;
04909 }
04910 iter = ao2_iterator_init(c, 0);
04911 for (; (info = ao2_iterator_next(&iter)); ao2_ref(info, -1)) {
04912 enum ast_channel_state search_state = 0;
04913 char match[AST_CHANNEL_NAME];
04914 struct ast_channel_iterator *chan_iter;
04915 struct timeval chantime = {0, };
04916
04917 switch (info->device_state) {
04918 case AST_DEVICE_RINGING:
04919 case AST_DEVICE_RINGINUSE:
04920
04921 search_state = AST_STATE_RINGING;
04922 break;
04923 case AST_DEVICE_BUSY:
04924
04925 search_state = AST_STATE_BUSY;
04926 break;
04927 case AST_DEVICE_ONHOLD:
04928 case AST_DEVICE_INUSE:
04929
04930 search_state = AST_STATE_UP;
04931 break;
04932 case AST_DEVICE_UNKNOWN:
04933 case AST_DEVICE_NOT_INUSE:
04934 case AST_DEVICE_INVALID:
04935 case AST_DEVICE_UNAVAILABLE:
04936 case AST_DEVICE_TOTAL :
04937
04938 continue;
04939 }
04940
04941
04942 snprintf(match, sizeof(match), "%s-", info->device_name);
04943 chan_iter = ast_channel_iterator_by_name_new(match, strlen(match));
04944 for (; (chan = ast_channel_iterator_next(chan_iter)); ast_channel_unref(chan)) {
04945 ast_channel_lock(chan);
04946
04947 if (search_state != ast_channel_state(chan)) {
04948 ast_channel_unlock(chan);
04949 continue;
04950 }
04951
04952 if (search_state != AST_STATE_RINGING) {
04953 ast_channel_unlock(chan);
04954 info->causing_channel = chan;
04955 break;
04956 }
04957
04958 if (!info->causing_channel) {
04959 chantime = ast_channel_creationtime(chan);
04960 ast_channel_ref(chan);
04961 info->causing_channel = chan;
04962 } else if (ast_tvcmp(ast_channel_creationtime(chan), chantime) < 0) {
04963 chantime = ast_channel_creationtime(chan);
04964 ast_channel_unref(info->causing_channel);
04965 ast_channel_ref(chan);
04966 info->causing_channel = chan;
04967 }
04968 ast_channel_unlock(chan);
04969 }
04970 ast_channel_iterator_destroy(chan_iter);
04971 }
04972 ao2_iterator_destroy(&iter);
04973 }
04974
04975 static int handle_statechange(void *datap)
04976 {
04977 struct ast_hint *hint;
04978 struct ast_str *hint_app;
04979 struct ast_hintdevice *device;
04980 struct ast_hintdevice *cmpdevice;
04981 struct statechange *sc = datap;
04982 struct ao2_iterator *dev_iter;
04983 struct ao2_iterator cb_iter;
04984 char context_name[AST_MAX_CONTEXT];
04985 char exten_name[AST_MAX_EXTENSION];
04986
04987 if (ao2_container_count(hintdevices) == 0) {
04988
04989 ast_free(sc);
04990 return 0;
04991 }
04992
04993 hint_app = ast_str_create(1024);
04994 if (!hint_app) {
04995 ast_free(sc);
04996 return -1;
04997 }
04998
04999 cmpdevice = ast_alloca(sizeof(*cmpdevice) + strlen(sc->dev));
05000 strcpy(cmpdevice->hintdevice, sc->dev);
05001
05002 ast_mutex_lock(&context_merge_lock);
05003 dev_iter = ao2_t_callback(hintdevices,
05004 OBJ_POINTER | OBJ_MULTIPLE,
05005 hintdevice_cmp_multiple,
05006 cmpdevice,
05007 "find devices in container");
05008 if (!dev_iter) {
05009 ast_mutex_unlock(&context_merge_lock);
05010 ast_free(hint_app);
05011 ast_free(sc);
05012 return -1;
05013 }
05014
05015 for (; (device = ao2_iterator_next(dev_iter)); ao2_t_ref(device, -1, "Next device")) {
05016 struct ast_state_cb *state_cb;
05017 int state;
05018 int same_state;
05019 struct ao2_container *device_state_info;
05020 int first_extended_cb_call = 1;
05021
05022 if (!device->hint) {
05023
05024 continue;
05025 }
05026 hint = device->hint;
05027
05028 ao2_lock(hint);
05029 if (!hint->exten) {
05030
05031 ao2_unlock(hint);
05032 continue;
05033 }
05034
05035
05036
05037
05038
05039 ast_copy_string(context_name,
05040 ast_get_context_name(ast_get_extension_context(hint->exten)),
05041 sizeof(context_name));
05042 ast_copy_string(exten_name, ast_get_extension_name(hint->exten),
05043 sizeof(exten_name));
05044 ast_str_set(&hint_app, 0, "%s", ast_get_extension_app(hint->exten));
05045 ao2_unlock(hint);
05046
05047
05048
05049
05050
05051
05052
05053
05054
05055
05056
05057 device_state_info = alloc_device_state_info();
05058 state = ast_extension_state3(hint_app, device_state_info);
05059 if ((same_state = state == hint->laststate) && (~state & AST_EXTENSION_RINGING)) {
05060 ao2_cleanup(device_state_info);
05061 continue;
05062 }
05063
05064
05065 hint->laststate = state;
05066
05067
05068 cb_iter = ao2_iterator_init(statecbs, 0);
05069 for (; !same_state && (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
05070 execute_state_callback(state_cb->change_cb,
05071 context_name,
05072 exten_name,
05073 state_cb->data,
05074 AST_HINT_UPDATE_DEVICE,
05075 hint,
05076 NULL);
05077 }
05078 ao2_iterator_destroy(&cb_iter);
05079
05080
05081
05082
05083
05084 cb_iter = ao2_iterator_init(hint->callbacks, 0);
05085 for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
05086 if (state_cb->extended && first_extended_cb_call) {
05087
05088 first_extended_cb_call = 0;
05089 get_device_state_causing_channels(device_state_info);
05090 }
05091 if (state_cb->extended || !same_state) {
05092 execute_state_callback(state_cb->change_cb,
05093 context_name,
05094 exten_name,
05095 state_cb->data,
05096 AST_HINT_UPDATE_DEVICE,
05097 hint,
05098 state_cb->extended ? device_state_info : NULL);
05099 }
05100 }
05101 ao2_iterator_destroy(&cb_iter);
05102
05103 ao2_cleanup(device_state_info);
05104 }
05105 ast_mutex_unlock(&context_merge_lock);
05106
05107 ao2_iterator_destroy(dev_iter);
05108 ast_free(hint_app);
05109 ast_free(sc);
05110 return 0;
05111 }
05112
05113
05114
05115
05116
05117
05118
05119
05120
05121 static void destroy_state_cb(void *doomed)
05122 {
05123 struct ast_state_cb *state_cb = doomed;
05124
05125 if (state_cb->destroy_cb) {
05126 state_cb->destroy_cb(state_cb->id, state_cb->data);
05127 }
05128 }
05129
05130
05131 static int extension_state_add_destroy(const char *context, const char *exten,
05132 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data, int extended)
05133 {
05134 struct ast_hint *hint;
05135 struct ast_state_cb *state_cb;
05136 struct ast_exten *e;
05137 int id;
05138
05139
05140 if (!context && !exten) {
05141
05142 ao2_lock(statecbs);
05143
05144
05145 ao2_find(statecbs, change_cb, OBJ_UNLINK | OBJ_NODATA);
05146
05147
05148 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
05149 ao2_unlock(statecbs);
05150 return -1;
05151 }
05152 state_cb->id = 0;
05153 state_cb->change_cb = change_cb;
05154 state_cb->destroy_cb = destroy_cb;
05155 state_cb->data = data;
05156 state_cb->extended = extended;
05157 ao2_link(statecbs, state_cb);
05158
05159 ao2_ref(state_cb, -1);
05160 ao2_unlock(statecbs);
05161 return 0;
05162 }
05163
05164 if (!context || !exten)
05165 return -1;
05166
05167
05168 e = ast_hint_extension(NULL, context, exten);
05169 if (!e) {
05170 return -1;
05171 }
05172
05173
05174
05175
05176
05177 if (e->exten[0] == '_') {
05178 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
05179 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
05180 e->registrar);
05181 e = ast_hint_extension(NULL, context, exten);
05182 if (!e || e->exten[0] == '_') {
05183 return -1;
05184 }
05185 }
05186
05187
05188 ao2_lock(hints);
05189 hint = ao2_find(hints, e, 0);
05190 if (!hint) {
05191 ao2_unlock(hints);
05192 return -1;
05193 }
05194
05195
05196 if (!(state_cb = ao2_alloc(sizeof(*state_cb), destroy_state_cb))) {
05197 ao2_ref(hint, -1);
05198 ao2_unlock(hints);
05199 return -1;
05200 }
05201 do {
05202 id = stateid++;
05203
05204 } while (id == -1 || id == 0);
05205 state_cb->id = id;
05206 state_cb->change_cb = change_cb;
05207 state_cb->destroy_cb = destroy_cb;
05208 state_cb->data = data;
05209 state_cb->extended = extended;
05210 ao2_link(hint->callbacks, state_cb);
05211
05212 ao2_ref(state_cb, -1);
05213 ao2_ref(hint, -1);
05214 ao2_unlock(hints);
05215
05216 return id;
05217 }
05218
05219
05220 int ast_extension_state_add_destroy(const char *context, const char *exten,
05221 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
05222 {
05223 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
05224 }
05225
05226
05227 int ast_extension_state_add(const char *context, const char *exten,
05228 ast_state_cb_type change_cb, void *data)
05229 {
05230 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
05231 }
05232
05233
05234 int ast_extension_state_add_destroy_extended(const char *context, const char *exten,
05235 ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
05236 {
05237 return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
05238 }
05239
05240
05241 int ast_extension_state_add_extended(const char *context, const char *exten,
05242 ast_state_cb_type change_cb, void *data)
05243 {
05244 return extension_state_add_destroy(context, exten, change_cb, NULL, data, 1);
05245 }
05246
05247
05248 static int find_hint_by_cb_id(void *obj, void *arg, int flags)
05249 {
05250 struct ast_state_cb *state_cb;
05251 const struct ast_hint *hint = obj;
05252 int *id = arg;
05253
05254 if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
05255 ao2_ref(state_cb, -1);
05256 return CMP_MATCH | CMP_STOP;
05257 }
05258
05259 return 0;
05260 }
05261
05262
05263 int ast_extension_state_del(int id, ast_state_cb_type change_cb)
05264 {
05265 struct ast_state_cb *p_cur;
05266 int ret = -1;
05267
05268 if (!id) {
05269 if (!change_cb) {
05270 return ret;
05271 }
05272 p_cur = ao2_find(statecbs, change_cb, OBJ_UNLINK);
05273 if (p_cur) {
05274 ret = 0;
05275 ao2_ref(p_cur, -1);
05276 }
05277 } else {
05278 struct ast_hint *hint;
05279
05280 ao2_lock(hints);
05281 hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
05282 if (hint) {
05283 p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
05284 if (p_cur) {
05285 ret = 0;
05286 ao2_ref(p_cur, -1);
05287 }
05288 ao2_ref(hint, -1);
05289 }
05290 ao2_unlock(hints);
05291 }
05292
05293 return ret;
05294 }
05295
05296 static int hint_id_cmp(void *obj, void *arg, int flags)
05297 {
05298 const struct ast_state_cb *cb = obj;
05299 int *id = arg;
05300
05301 return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
05302 }
05303
05304
05305
05306
05307
05308
05309
05310
05311
05312 static void destroy_hint(void *obj)
05313 {
05314 struct ast_hint *hint = obj;
05315
05316 if (hint->callbacks) {
05317 struct ast_state_cb *state_cb;
05318 const char *context_name;
05319 const char *exten_name;
05320
05321 if (hint->exten) {
05322 context_name = ast_get_context_name(ast_get_extension_context(hint->exten));
05323 exten_name = ast_get_extension_name(hint->exten);
05324 hint->exten = NULL;
05325 } else {
05326
05327 context_name = hint->context_name;
05328 exten_name = hint->exten_name;
05329 }
05330 hint->laststate = AST_EXTENSION_DEACTIVATED;
05331 while ((state_cb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
05332
05333 execute_state_callback(state_cb->change_cb,
05334 context_name,
05335 exten_name,
05336 state_cb->data,
05337 AST_HINT_UPDATE_DEVICE,
05338 hint,
05339 NULL);
05340 ao2_ref(state_cb, -1);
05341 }
05342 ao2_ref(hint->callbacks, -1);
05343 }
05344 ast_free(hint->last_presence_subtype);
05345 ast_free(hint->last_presence_message);
05346 }
05347
05348
05349 static int ast_remove_hint(struct ast_exten *e)
05350 {
05351
05352 struct ast_hint *hint;
05353
05354 if (!e) {
05355 return -1;
05356 }
05357
05358 hint = ao2_find(hints, e, OBJ_UNLINK);
05359 if (!hint) {
05360 return -1;
05361 }
05362
05363 remove_hintdevice(hint);
05364
05365
05366
05367
05368
05369 ao2_lock(hint);
05370 ast_copy_string(hint->context_name,
05371 ast_get_context_name(ast_get_extension_context(hint->exten)),
05372 sizeof(hint->context_name));
05373 ast_copy_string(hint->exten_name, ast_get_extension_name(hint->exten),
05374 sizeof(hint->exten_name));
05375 hint->exten = NULL;
05376 ao2_unlock(hint);
05377
05378 ao2_ref(hint, -1);
05379
05380 return 0;
05381 }
05382
05383
05384 static int ast_add_hint(struct ast_exten *e)
05385 {
05386 struct ast_hint *hint_new;
05387 struct ast_hint *hint_found;
05388 char *message = NULL;
05389 char *subtype = NULL;
05390 int presence_state;
05391
05392 if (!e) {
05393 return -1;
05394 }
05395
05396
05397
05398
05399
05400
05401 hint_new = ao2_alloc(sizeof(*hint_new), destroy_hint);
05402 if (!hint_new) {
05403 return -1;
05404 }
05405
05406
05407 hint_new->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp);
05408 if (!hint_new->callbacks) {
05409 ao2_ref(hint_new, -1);
05410 return -1;
05411 }
05412 hint_new->exten = e;
05413 hint_new->laststate = ast_extension_state2(e, NULL);
05414 if ((presence_state = extension_presence_state_helper(e, &subtype, &message)) > 0) {
05415 hint_new->last_presence_state = presence_state;
05416 hint_new->last_presence_subtype = subtype;
05417 hint_new->last_presence_message = message;
05418 message = subtype = NULL;
05419 }
05420
05421
05422 ao2_lock(hints);
05423
05424
05425 hint_found = ao2_find(hints, e, 0);
05426 if (hint_found) {
05427 ao2_ref(hint_found, -1);
05428 ao2_unlock(hints);
05429 ao2_ref(hint_new, -1);
05430 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n",
05431 ast_get_extension_name(e), ast_get_extension_app(e));
05432 return -1;
05433 }
05434
05435
05436 ast_debug(2, "HINTS: Adding hint %s: %s\n",
05437 ast_get_extension_name(e), ast_get_extension_app(e));
05438 ao2_link(hints, hint_new);
05439 if (add_hintdevice(hint_new, ast_get_extension_app(e))) {
05440 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
05441 ast_get_extension_name(e),
05442 ast_get_context_name(ast_get_extension_context(e)));
05443 }
05444
05445 ao2_unlock(hints);
05446 ao2_ref(hint_new, -1);
05447
05448 return 0;
05449 }
05450
05451
05452 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
05453 {
05454 struct ast_hint *hint;
05455
05456 if (!oe || !ne) {
05457 return -1;
05458 }
05459
05460 ao2_lock(hints);
05461
05462
05463
05464
05465
05466 hint = ao2_find(hints, oe, OBJ_UNLINK);
05467 if (!hint) {
05468 ao2_unlock(hints);
05469 return -1;
05470 }
05471
05472 remove_hintdevice(hint);
05473
05474
05475 ao2_lock(hint);
05476 hint->exten = ne;
05477 ao2_unlock(hint);
05478 ao2_link(hints, hint);
05479 if (add_hintdevice(hint, ast_get_extension_app(ne))) {
05480 ast_log(LOG_WARNING, "Could not add devices for hint: %s@%s.\n",
05481 ast_get_extension_name(ne),
05482 ast_get_context_name(ast_get_extension_context(ne)));
05483 }
05484
05485 ao2_unlock(hints);
05486 ao2_ref(hint, -1);
05487
05488 return 0;
05489 }
05490
05491
05492
05493 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
05494 {
05495 struct ast_exten *e = ast_hint_extension(c, context, exten);
05496
05497 if (e) {
05498 if (hint)
05499 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
05500 if (name) {
05501 const char *tmp = ast_get_extension_app_data(e);
05502 if (tmp)
05503 ast_copy_string(name, tmp, namesize);
05504 }
05505 return -1;
05506 }
05507 return 0;
05508 }
05509
05510
05511 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)
05512 {
05513 struct ast_exten *e = ast_hint_extension(c, context, exten);
05514
05515 if (!e) {
05516 return 0;
05517 }
05518
05519 if (hint) {
05520 ast_str_set(hint, hintsize, "%s", ast_get_extension_app(e));
05521 }
05522 if (name) {
05523 const char *tmp = ast_get_extension_app_data(e);
05524 if (tmp) {
05525 ast_str_set(name, namesize, "%s", tmp);
05526 }
05527 }
05528 return -1;
05529 }
05530
05531 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
05532 {
05533 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
05534 }
05535
05536 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
05537 {
05538 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
05539 }
05540
05541 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
05542 {
05543 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
05544 }
05545
05546 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
05547 {
05548 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
05549 }
05550
05551 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
05552 {
05553 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
05554 }
05555
05556 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)
05557 {
05558 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
05559 }
05560
05561 void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context)
05562 {
05563 int autoloopflag;
05564 int found;
05565 int spawn_error;
05566
05567 ast_channel_lock(chan);
05568
05569 if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
05570 ast_cdr_end(ast_channel_cdr(chan));
05571 }
05572
05573
05574 if (context != ast_channel_context(chan)) {
05575 ast_channel_context_set(chan, context);
05576 }
05577 ast_channel_exten_set(chan, "h");
05578 ast_channel_priority_set(chan, 1);
05579
05580
05581
05582
05583
05584 ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
05585
05586
05587 autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
05588 ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
05589 ast_channel_unlock(chan);
05590
05591 for (;;) {
05592 spawn_error = ast_spawn_extension(chan, ast_channel_context(chan),
05593 ast_channel_exten(chan), ast_channel_priority(chan),
05594 S_COR(ast_channel_caller(chan)->id.number.valid,
05595 ast_channel_caller(chan)->id.number.str, NULL), &found, 1);
05596
05597 ast_channel_lock(chan);
05598 if (spawn_error) {
05599
05600 break;
05601 }
05602 ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
05603 ast_channel_unlock(chan);
05604 }
05605 if (found && spawn_error) {
05606
05607 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n",
05608 ast_channel_context(chan), ast_channel_exten(chan),
05609 ast_channel_priority(chan), ast_channel_name(chan));
05610 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
05611 ast_channel_context(chan), ast_channel_exten(chan),
05612 ast_channel_priority(chan), ast_channel_name(chan));
05613 }
05614
05615
05616 ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN);
05617
05618
05619 ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
05620 ast_channel_unlock(chan);
05621 }
05622
05623 int ast_pbx_hangup_handler_run(struct ast_channel *chan)
05624 {
05625 struct ast_hangup_handler_list *handlers;
05626 struct ast_hangup_handler *h_handler;
05627
05628 ast_channel_lock(chan);
05629 handlers = ast_channel_hangup_handlers(chan);
05630 if (AST_LIST_EMPTY(handlers)) {
05631 ast_channel_unlock(chan);
05632 return 0;
05633 }
05634
05635 if (ast_channel_cdr(chan) && ast_opt_end_cdr_before_h_exten) {
05636 ast_cdr_end(ast_channel_cdr(chan));
05637 }
05638
05639
05640
05641
05642
05643 ast_softhangup_nolock(chan, AST_SOFTHANGUP_APPUNLOAD);
05644
05645 for (;;) {
05646 handlers = ast_channel_hangup_handlers(chan);
05647 h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
05648 if (!h_handler) {
05649 break;
05650 }
05651
05652
05653
05654
05655
05656
05657
05658
05659
05660
05661
05662 manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerRun",
05663 "Channel: %s\r\n"
05664 "Uniqueid: %s\r\n"
05665 "Handler: %s\r\n",
05666 ast_channel_name(chan),
05667 ast_channel_uniqueid(chan),
05668 h_handler->args);
05669 ast_channel_unlock(chan);
05670
05671 ast_app_exec_sub(NULL, chan, h_handler->args, 1);
05672 ast_free(h_handler);
05673
05674 ast_channel_lock(chan);
05675 }
05676 ast_channel_unlock(chan);
05677 return 1;
05678 }
05679
05680 void ast_pbx_hangup_handler_init(struct ast_channel *chan)
05681 {
05682 struct ast_hangup_handler_list *handlers;
05683
05684 handlers = ast_channel_hangup_handlers(chan);
05685 AST_LIST_HEAD_INIT_NOLOCK(handlers);
05686 }
05687
05688 void ast_pbx_hangup_handler_destroy(struct ast_channel *chan)
05689 {
05690 struct ast_hangup_handler_list *handlers;
05691 struct ast_hangup_handler *h_handler;
05692
05693 ast_channel_lock(chan);
05694
05695
05696 handlers = ast_channel_hangup_handlers(chan);
05697 while ((h_handler = AST_LIST_REMOVE_HEAD(handlers, node))) {
05698 ast_free(h_handler);
05699 }
05700
05701 ast_channel_unlock(chan);
05702 }
05703
05704 int ast_pbx_hangup_handler_pop(struct ast_channel *chan)
05705 {
05706 struct ast_hangup_handler_list *handlers;
05707 struct ast_hangup_handler *h_handler;
05708
05709 ast_channel_lock(chan);
05710 handlers = ast_channel_hangup_handlers(chan);
05711 h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
05712 if (h_handler) {
05713
05714
05715
05716
05717
05718
05719
05720
05721
05722
05723
05724
05725
05726
05727
05728
05729
05730 manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPop",
05731 "Channel: %s\r\n"
05732 "Uniqueid: %s\r\n"
05733 "Handler: %s\r\n",
05734 ast_channel_name(chan),
05735 ast_channel_uniqueid(chan),
05736 h_handler->args);
05737 }
05738 ast_channel_unlock(chan);
05739 if (h_handler) {
05740 ast_free(h_handler);
05741 return 1;
05742 }
05743 return 0;
05744 }
05745
05746 void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler)
05747 {
05748 struct ast_hangup_handler_list *handlers;
05749 struct ast_hangup_handler *h_handler;
05750 const char *expanded_handler;
05751
05752 if (ast_strlen_zero(handler)) {
05753 return;
05754 }
05755
05756 expanded_handler = ast_app_expand_sub_args(chan, handler);
05757 if (!expanded_handler) {
05758 return;
05759 }
05760 h_handler = ast_malloc(sizeof(*h_handler) + 1 + strlen(expanded_handler));
05761 if (!h_handler) {
05762 ast_free((char *) expanded_handler);
05763 return;
05764 }
05765 strcpy(h_handler->args, expanded_handler);
05766 ast_free((char *) expanded_handler);
05767
05768 ast_channel_lock(chan);
05769
05770 handlers = ast_channel_hangup_handlers(chan);
05771 AST_LIST_INSERT_HEAD(handlers, h_handler, node);
05772
05773
05774
05775
05776
05777
05778
05779
05780
05781
05782
05783
05784
05785
05786
05787
05788
05789
05790 manager_event(EVENT_FLAG_DIALPLAN, "HangupHandlerPush",
05791 "Channel: %s\r\n"
05792 "Uniqueid: %s\r\n"
05793 "Handler: %s\r\n",
05794 ast_channel_name(chan),
05795 ast_channel_uniqueid(chan),
05796 h_handler->args);
05797
05798 ast_channel_unlock(chan);
05799 }
05800
05801 #define HANDLER_FORMAT "%-30s %s\n"
05802
05803
05804
05805
05806
05807
05808
05809
05810
05811
05812 static void ast_pbx_hangup_handler_headers(int fd)
05813 {
05814 ast_cli(fd, HANDLER_FORMAT, "Channel", "Handler");
05815 }
05816
05817
05818
05819
05820
05821
05822
05823
05824
05825
05826
05827 static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
05828 {
05829 struct ast_hangup_handler_list *handlers;
05830 struct ast_hangup_handler *h_handler;
05831 int first = 1;
05832
05833 ast_channel_lock(chan);
05834 handlers = ast_channel_hangup_handlers(chan);
05835 AST_LIST_TRAVERSE(handlers, h_handler, node) {
05836 ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
05837 first = 0;
05838 }
05839 ast_channel_unlock(chan);
05840 }
05841
05842
05843
05844
05845 static char *handle_show_hangup_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05846 {
05847 struct ast_channel *chan;
05848
05849 switch (cmd) {
05850 case CLI_INIT:
05851 e->command = "core show hanguphandlers";
05852 e->usage =
05853 "Usage: core show hanguphandlers <channel>\n"
05854 " Show hangup handlers of a specified channel.\n";
05855 return NULL;
05856 case CLI_GENERATE:
05857 return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
05858 }
05859
05860 if (a->argc < 4) {
05861 return CLI_SHOWUSAGE;
05862 }
05863
05864 chan = ast_channel_get_by_name(a->argv[3]);
05865 if (!chan) {
05866 ast_cli(a->fd, "Channel does not exist.\n");
05867 return CLI_FAILURE;
05868 }
05869
05870 ast_pbx_hangup_handler_headers(a->fd);
05871 ast_pbx_hangup_handler_show(a->fd, chan);
05872
05873 ast_channel_unref(chan);
05874
05875 return CLI_SUCCESS;
05876 }
05877
05878
05879
05880
05881 static char *handle_show_hangup_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05882 {
05883 struct ast_channel_iterator *iter;
05884 struct ast_channel *chan;
05885
05886 switch (cmd) {
05887 case CLI_INIT:
05888 e->command = "core show hanguphandlers all";
05889 e->usage =
05890 "Usage: core show hanguphandlers all\n"
05891 " Show hangup handlers for all channels.\n";
05892 return NULL;
05893 case CLI_GENERATE:
05894 return ast_complete_channels(a->line, a->word, a->pos, a->n, e->args);
05895 }
05896
05897 if (a->argc < 4) {
05898 return CLI_SHOWUSAGE;
05899 }
05900
05901 iter = ast_channel_iterator_all_new();
05902 if (!iter) {
05903 return CLI_FAILURE;
05904 }
05905
05906 ast_pbx_hangup_handler_headers(a->fd);
05907 for (; (chan = ast_channel_iterator_next(iter)); ast_channel_unref(chan)) {
05908 ast_pbx_hangup_handler_show(a->fd, chan);
05909 }
05910 ast_channel_iterator_destroy(iter);
05911
05912 return CLI_SUCCESS;
05913 }
05914
05915
05916 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
05917 {
05918 ast_channel_lock(c);
05919 ast_channel_exten_set(c, exten);
05920 ast_channel_priority_set(c, pri);
05921 ast_channel_unlock(c);
05922 }
05923
05924
05925
05926
05927
05928
05929
05930
05931 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
05932 {
05933 int digit;
05934
05935 buf[pos] = '\0';
05936 while (ast_matchmore_extension(c, ast_channel_context(c), buf, 1,
05937 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
05938
05939
05940 digit = ast_waitfordigit(c, waittime);
05941 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
05942 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
05943 } else {
05944 if (!digit)
05945 break;
05946 if (digit < 0)
05947 return -1;
05948 if (pos < buflen - 1) {
05949 buf[pos++] = digit;
05950 buf[pos] = '\0';
05951 }
05952 waittime = ast_channel_pbx(c)->dtimeoutms;
05953 }
05954 }
05955 return 0;
05956 }
05957
05958 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
05959 struct ast_pbx_args *args)
05960 {
05961 int found = 0;
05962 int res = 0;
05963 int autoloopflag;
05964 int error = 0;
05965 struct ast_pbx *pbx;
05966 struct ast_callid *callid;
05967
05968
05969 if (ast_channel_pbx(c)) {
05970 ast_log(LOG_WARNING, "%s already has PBX structure??\n", ast_channel_name(c));
05971
05972 ast_free(ast_channel_pbx(c));
05973 }
05974 if (!(pbx = ast_calloc(1, sizeof(*pbx)))) {
05975 return -1;
05976 }
05977
05978 callid = ast_read_threadstorage_callid();
05979
05980 if (!callid) {
05981
05982
05983
05984 callid = ast_channel_callid(c);
05985 if (!callid) {
05986 callid = ast_create_callid();
05987 if (callid) {
05988 ast_channel_callid_set(c, callid);
05989 }
05990 }
05991 ast_callid_threadassoc_add(callid);
05992 callid = ast_callid_unref(callid);
05993 } else {
05994
05995 ast_callid_unref(callid);
05996 }
05997
05998 ast_channel_pbx_set(c, pbx);
05999
06000 ast_channel_pbx(c)->rtimeoutms = 10000;
06001 ast_channel_pbx(c)->dtimeoutms = 5000;
06002
06003 autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
06004 ast_set_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
06005
06006 if (ast_strlen_zero(ast_channel_exten(c))) {
06007
06008 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));
06009
06010
06011
06012
06013 set_ext_pri(c, "s", 1);
06014 }
06015
06016 ast_channel_lock(c);
06017 if (ast_channel_cdr(c)) {
06018
06019 ast_cdr_update(c);
06020 }
06021 ast_channel_unlock(c);
06022 for (;;) {
06023 char dst_exten[256];
06024 int pos = 0;
06025 int digit = 0;
06026 int invalid = 0;
06027 int timeout = 0;
06028
06029
06030 dst_exten[pos] = '\0';
06031
06032
06033 while (!(res = ast_spawn_extension(c, ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c),
06034 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL),
06035 &found, 1))) {
06036 if (!ast_check_hangup(c)) {
06037 ast_channel_priority_set(c, ast_channel_priority(c) + 1);
06038 continue;
06039 }
06040
06041
06042 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
06043 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
06044 continue;
06045 }
06046 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
06047 if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
06048 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06049 set_ext_pri(c, "T", 1);
06050
06051 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06052 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06053 continue;
06054 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06055 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06056 raise_exception(c, "ABSOLUTETIMEOUT", 1);
06057
06058 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06059 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06060 continue;
06061 }
06062
06063
06064 error = 1;
06065 break;
06066 }
06067 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
06068 ast_channel_exten(c), ast_channel_priority(c));
06069 error = 1;
06070 break;
06071 }
06072 if (found && res) {
06073
06074 if (strchr("0123456789ABCDEF*#", res)) {
06075 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
06076 pos = 0;
06077 dst_exten[pos++] = digit = res;
06078 dst_exten[pos] = '\0';
06079 } else if (res == AST_PBX_INCOMPLETE) {
06080 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));
06081 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));
06082
06083
06084 if (!ast_matchmore_extension(c, ast_channel_context(c), ast_channel_exten(c), 1,
06085 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06086 invalid = 1;
06087 } else {
06088 ast_copy_string(dst_exten, ast_channel_exten(c), sizeof(dst_exten));
06089 digit = 1;
06090 pos = strlen(dst_exten);
06091 }
06092 } else {
06093 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));
06094 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));
06095
06096 if ((res == AST_PBX_ERROR)
06097 && ast_exists_extension(c, ast_channel_context(c), "e", 1,
06098 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06099
06100 if (!strcmp(ast_channel_exten(c), "e")) {
06101 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));
06102 error = 1;
06103 } else {
06104 raise_exception(c, "ERROR", 1);
06105 continue;
06106 }
06107 }
06108
06109 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_ASYNCGOTO) {
06110 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
06111 continue;
06112 }
06113 if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
06114 if (ast_exists_extension(c, ast_channel_context(c), "T", 1,
06115 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06116 set_ext_pri(c, "T", 1);
06117
06118 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06119 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06120 continue;
06121 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06122 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06123 raise_exception(c, "ABSOLUTETIMEOUT", 1);
06124
06125 memset(ast_channel_whentohangup(c), 0, sizeof(*ast_channel_whentohangup(c)));
06126 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06127 continue;
06128 }
06129
06130 }
06131 ast_channel_lock(c);
06132 if (ast_channel_cdr(c)) {
06133 ast_cdr_update(c);
06134 }
06135 ast_channel_unlock(c);
06136 error = 1;
06137 break;
06138 }
06139 }
06140 if (error)
06141 break;
06142
06143
06144
06145
06146
06147
06148 if (invalid
06149 || (ast_strlen_zero(dst_exten) &&
06150 !ast_exists_extension(c, ast_channel_context(c), ast_channel_exten(c), 1,
06151 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL)))) {
06152
06153
06154
06155
06156
06157 if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
06158 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06159 ast_verb(3, "Channel '%s' sent to invalid extension: context,exten,priority=%s,%s,%d\n",
06160 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
06161 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", ast_channel_exten(c));
06162 set_ext_pri(c, "i", 1);
06163 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06164 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06165 raise_exception(c, "INVALID", 1);
06166 } else {
06167 ast_log(LOG_WARNING, "Channel '%s' sent to invalid extension but no invalid handler: context,exten,priority=%s,%s,%d\n",
06168 ast_channel_name(c), ast_channel_context(c), ast_channel_exten(c), ast_channel_priority(c));
06169 error = 1;
06170 break;
06171 }
06172 } else if (ast_channel_softhangup_internal_flag(c) & AST_SOFTHANGUP_TIMEOUT) {
06173
06174 ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
06175 } else {
06176 int waittime = 0;
06177 if (digit)
06178 waittime = ast_channel_pbx(c)->dtimeoutms;
06179 else if (!autofallthrough)
06180 waittime = ast_channel_pbx(c)->rtimeoutms;
06181 if (!waittime) {
06182 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
06183 if (!status)
06184 status = "UNKNOWN";
06185 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", ast_channel_name(c), status);
06186 if (!strcasecmp(status, "CONGESTION"))
06187 res = pbx_builtin_congestion(c, "10");
06188 else if (!strcasecmp(status, "CHANUNAVAIL"))
06189 res = pbx_builtin_congestion(c, "10");
06190 else if (!strcasecmp(status, "BUSY"))
06191 res = pbx_builtin_busy(c, "10");
06192 error = 1;
06193 break;
06194 }
06195
06196 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
06197 break;
06198 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
06199 timeout = 1;
06200 if (!timeout
06201 && ast_exists_extension(c, ast_channel_context(c), dst_exten, 1,
06202 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06203 set_ext_pri(c, dst_exten, 1);
06204 } else {
06205
06206 if (!timeout && !ast_strlen_zero(dst_exten)) {
06207
06208 if (ast_exists_extension(c, ast_channel_context(c), "i", 1,
06209 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06210 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, ast_channel_context(c), ast_channel_name(c));
06211 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
06212 set_ext_pri(c, "i", 1);
06213 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06214 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06215 raise_exception(c, "INVALID", 1);
06216 } else {
06217 ast_log(LOG_WARNING,
06218 "Invalid extension '%s', but no rule 'i' or 'e' in context '%s'\n",
06219 dst_exten, ast_channel_context(c));
06220 found = 1;
06221 break;
06222 }
06223 } else {
06224
06225 if (ast_exists_extension(c, ast_channel_context(c), "t", 1,
06226 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06227 ast_verb(3, "Timeout on %s\n", ast_channel_name(c));
06228 set_ext_pri(c, "t", 1);
06229 } else if (ast_exists_extension(c, ast_channel_context(c), "e", 1,
06230 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
06231 raise_exception(c, "RESPONSETIMEOUT", 1);
06232 } else {
06233 ast_log(LOG_WARNING,
06234 "Timeout, but no rule 't' or 'e' in context '%s'\n",
06235 ast_channel_context(c));
06236 found = 1;
06237 break;
06238 }
06239 }
06240 }
06241 ast_channel_lock(c);
06242 if (ast_channel_cdr(c)) {
06243 ast_verb(2, "CDR updated on %s\n",ast_channel_name(c));
06244 ast_cdr_update(c);
06245 }
06246 ast_channel_unlock(c);
06247 }
06248 }
06249
06250 if (!found && !error) {
06251 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", ast_channel_name(c));
06252 }
06253
06254 if (!args || !args->no_hangup_chan) {
06255 ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
06256 if (!ast_test_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN)
06257 && ast_exists_extension(c, ast_channel_context(c), "h", 1,
06258 S_COR(ast_channel_caller(c)->id.number.valid,
06259 ast_channel_caller(c)->id.number.str, NULL))) {
06260 ast_pbx_h_exten_run(c, ast_channel_context(c));
06261 }
06262 ast_pbx_hangup_handler_run(c);
06263 }
06264
06265 ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP);
06266 ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN);
06267 pbx_destroy(ast_channel_pbx(c));
06268 ast_channel_pbx_set(c, NULL);
06269
06270 if (!args || !args->no_hangup_chan) {
06271 ast_hangup(c);
06272 }
06273
06274 return 0;
06275 }
06276
06277
06278
06279
06280
06281
06282 static int increase_call_count(const struct ast_channel *c)
06283 {
06284 int failed = 0;
06285 double curloadavg;
06286 #if defined(HAVE_SYSINFO)
06287 long curfreemem;
06288 struct sysinfo sys_info;
06289 #endif
06290
06291 ast_mutex_lock(&maxcalllock);
06292 if (option_maxcalls) {
06293 if (countcalls >= option_maxcalls) {
06294 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, ast_channel_name(c));
06295 failed = -1;
06296 }
06297 }
06298 if (option_maxload) {
06299 getloadavg(&curloadavg, 1);
06300 if (curloadavg >= option_maxload) {
06301 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, ast_channel_name(c), curloadavg);
06302 failed = -1;
06303 }
06304 }
06305 #if defined(HAVE_SYSINFO)
06306 if (option_minmemfree) {
06307 if (!sysinfo(&sys_info)) {
06308
06309
06310 curfreemem = sys_info.freeram * sys_info.mem_unit;
06311 curfreemem /= 1024 * 1024;
06312 if (curfreemem < option_minmemfree) {
06313 ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
06314 failed = -1;
06315 }
06316 }
06317 }
06318 #endif
06319
06320 if (!failed) {
06321 countcalls++;
06322 totalcalls++;
06323 }
06324 ast_mutex_unlock(&maxcalllock);
06325
06326 return failed;
06327 }
06328
06329 static void decrease_call_count(void)
06330 {
06331 ast_mutex_lock(&maxcalllock);
06332 if (countcalls > 0)
06333 countcalls--;
06334 ast_mutex_unlock(&maxcalllock);
06335 }
06336
06337 static void destroy_exten(struct ast_exten *e)
06338 {
06339 if (e->priority == PRIORITY_HINT)
06340 ast_remove_hint(e);
06341
06342 if (e->peer_table)
06343 ast_hashtab_destroy(e->peer_table,0);
06344 if (e->peer_label_table)
06345 ast_hashtab_destroy(e->peer_label_table, 0);
06346 if (e->datad)
06347 e->datad(e->data);
06348 ast_free(e);
06349 }
06350
06351 static void *pbx_thread(void *data)
06352 {
06353
06354
06355
06356
06357
06358
06359
06360
06361 struct ast_channel *c = data;
06362
06363 __ast_pbx_run(c, NULL);
06364 decrease_call_count();
06365
06366 pthread_exit(NULL);
06367
06368 return NULL;
06369 }
06370
06371 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
06372 {
06373 pthread_t t;
06374
06375 if (!c) {
06376 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
06377 return AST_PBX_FAILED;
06378 }
06379
06380 if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
06381 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
06382 return AST_PBX_FAILED;
06383 }
06384
06385 if (increase_call_count(c))
06386 return AST_PBX_CALL_LIMIT;
06387
06388
06389 if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
06390 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
06391 decrease_call_count();
06392 return AST_PBX_FAILED;
06393 }
06394
06395 return AST_PBX_SUCCESS;
06396 }
06397
06398 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
06399 {
06400 enum ast_pbx_result res = AST_PBX_SUCCESS;
06401
06402 if (!ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
06403 ast_log(LOG_WARNING, "PBX requires Asterisk to be fully booted\n");
06404 return AST_PBX_FAILED;
06405 }
06406
06407 if (increase_call_count(c)) {
06408 return AST_PBX_CALL_LIMIT;
06409 }
06410
06411 res = __ast_pbx_run(c, args);
06412
06413 decrease_call_count();
06414
06415 return res;
06416 }
06417
06418 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
06419 {
06420 return ast_pbx_run_args(c, NULL);
06421 }
06422
06423 int ast_active_calls(void)
06424 {
06425 return countcalls;
06426 }
06427
06428 int ast_processed_calls(void)
06429 {
06430 return totalcalls;
06431 }
06432
06433 int pbx_set_autofallthrough(int newval)
06434 {
06435 int oldval = autofallthrough;
06436 autofallthrough = newval;
06437 return oldval;
06438 }
06439
06440 int pbx_set_extenpatternmatchnew(int newval)
06441 {
06442 int oldval = extenpatternmatchnew;
06443 extenpatternmatchnew = newval;
06444 return oldval;
06445 }
06446
06447 void pbx_set_overrideswitch(const char *newval)
06448 {
06449 if (overrideswitch) {
06450 ast_free(overrideswitch);
06451 }
06452 if (!ast_strlen_zero(newval)) {
06453 overrideswitch = ast_strdup(newval);
06454 } else {
06455 overrideswitch = NULL;
06456 }
06457 }
06458
06459
06460
06461
06462
06463 static struct ast_context *find_context(const char *context)
06464 {
06465 struct fake_context item;
06466
06467 ast_copy_string(item.name, context, sizeof(item.name));
06468
06469 return ast_hashtab_lookup(contexts_table, &item);
06470 }
06471
06472
06473
06474
06475
06476
06477 static struct ast_context *find_context_locked(const char *context)
06478 {
06479 struct ast_context *c;
06480 struct fake_context item;
06481
06482 ast_copy_string(item.name, context, sizeof(item.name));
06483
06484 ast_rdlock_contexts();
06485 c = ast_hashtab_lookup(contexts_table, &item);
06486 if (!c) {
06487 ast_unlock_contexts();
06488 }
06489
06490 return c;
06491 }
06492
06493
06494
06495
06496
06497
06498
06499 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
06500 {
06501 int ret = -1;
06502 struct ast_context *c;
06503
06504 c = find_context_locked(context);
06505 if (c) {
06506
06507 ret = ast_context_remove_include2(c, include, registrar);
06508 ast_unlock_contexts();
06509 }
06510 return ret;
06511 }
06512
06513
06514
06515
06516
06517
06518
06519
06520
06521
06522 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
06523 {
06524 struct ast_include *i, *pi = NULL;
06525 int ret = -1;
06526
06527 ast_wrlock_context(con);
06528
06529
06530 for (i = con->includes; i; pi = i, i = i->next) {
06531 if (!strcmp(i->name, include) &&
06532 (!registrar || !strcmp(i->registrar, registrar))) {
06533
06534 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
06535 if (pi)
06536 pi->next = i->next;
06537 else
06538 con->includes = i->next;
06539
06540 ast_destroy_timing(&(i->timing));
06541 ast_free(i);
06542 ret = 0;
06543 break;
06544 }
06545 }
06546
06547 ast_unlock_context(con);
06548
06549 return ret;
06550 }
06551
06552
06553
06554
06555
06556
06557 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
06558 {
06559 int ret = -1;
06560 struct ast_context *c;
06561
06562 c = find_context_locked(context);
06563 if (c) {
06564
06565 ret = ast_context_remove_switch2(c, sw, data, registrar);
06566 ast_unlock_contexts();
06567 }
06568 return ret;
06569 }
06570
06571
06572
06573
06574
06575
06576
06577
06578
06579 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
06580 {
06581 struct ast_sw *i;
06582 int ret = -1;
06583
06584 ast_wrlock_context(con);
06585
06586
06587 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
06588 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
06589 (!registrar || !strcmp(i->registrar, registrar))) {
06590
06591 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
06592 AST_LIST_REMOVE_CURRENT(list);
06593 ast_free(i);
06594 ret = 0;
06595 break;
06596 }
06597 }
06598 AST_LIST_TRAVERSE_SAFE_END;
06599
06600 ast_unlock_context(con);
06601
06602 return ret;
06603 }
06604
06605
06606 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
06607 {
06608 return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
06609 }
06610
06611 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
06612 {
06613 int ret = -1;
06614 struct ast_context *c;
06615
06616 c = find_context_locked(context);
06617 if (c) {
06618 ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid,
06619 matchcallerid, registrar, 0);
06620 ast_unlock_contexts();
06621 }
06622
06623 return ret;
06624 }
06625
06626
06627
06628
06629
06630
06631
06632
06633
06634
06635
06636 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
06637 {
06638 return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
06639 }
06640
06641 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)
06642 {
06643 struct ast_exten *exten, *prev_exten = NULL;
06644 struct ast_exten *peer;
06645 struct ast_exten ex, *exten2, *exten3;
06646 char dummy_name[1024];
06647 struct ast_exten *previous_peer = NULL;
06648 struct ast_exten *next_peer = NULL;
06649 int found = 0;
06650
06651 if (!already_locked)
06652 ast_wrlock_context(con);
06653
06654
06655
06656
06657
06658 #ifdef NEED_DEBUG
06659 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
06660 #endif
06661 #ifdef CONTEXT_DEBUG
06662 check_contexts(__FILE__, __LINE__);
06663 #endif
06664
06665 ex.exten = dummy_name;
06666 ex.matchcid = matchcallerid && !ast_strlen_zero(callerid);
06667 ex.cidmatch = callerid;
06668 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
06669 exten = ast_hashtab_lookup(con->root_table, &ex);
06670 if (exten) {
06671 if (priority == 0) {
06672 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
06673 if (!exten2)
06674 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);
06675 if (con->pattern_tree) {
06676 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
06677
06678 if (x->exten) {
06679 x->deleted = 1;
06680 x->exten = 0;
06681 } else {
06682 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
06683 }
06684 }
06685 } else {
06686 ex.priority = priority;
06687 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
06688 if (exten2) {
06689
06690 if (exten2->label) {
06691 exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
06692 if (!exten3)
06693 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);
06694 }
06695
06696 exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
06697 if (!exten3)
06698 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);
06699 if (exten2 == exten && exten2->peer) {
06700 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
06701 ast_hashtab_insert_immediate(con->root_table, exten2->peer);
06702 }
06703 if (ast_hashtab_size(exten->peer_table) == 0) {
06704
06705
06706 exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
06707 if (!exten3)
06708 ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
06709 if (con->pattern_tree) {
06710 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
06711 if (x->exten) {
06712 x->deleted = 1;
06713 x->exten = 0;
06714 }
06715 }
06716 }
06717 } else {
06718 ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
06719 priority, exten->exten, con->name);
06720 }
06721 }
06722 } else {
06723
06724 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
06725 extension, con->name);
06726 }
06727 #ifdef NEED_DEBUG
06728 if (con->pattern_tree) {
06729 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
06730 log_match_char_tree(con->pattern_tree, " ");
06731 }
06732 #endif
06733
06734
06735 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
06736 if (!strcmp(exten->exten, extension) &&
06737 (!registrar || !strcmp(exten->registrar, registrar)) &&
06738 (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
06739 break;
06740 }
06741 if (!exten) {
06742
06743 if (!already_locked)
06744 ast_unlock_context(con);
06745 return -1;
06746 }
06747
06748
06749 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
06750 peer && !strcmp(peer->exten, extension) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
06751 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
06752 if ((priority == 0 || peer->priority == priority) &&
06753 (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
06754 (!registrar || !strcmp(peer->registrar, registrar) )) {
06755 found = 1;
06756
06757
06758 if (!previous_peer) {
06759
06760
06761
06762
06763 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
06764 if (peer->peer) {
06765
06766
06767 peer->peer->peer_table = peer->peer_table;
06768 peer->peer->peer_label_table = peer->peer_label_table;
06769 peer->peer_table = NULL;
06770 peer->peer_label_table = NULL;
06771 }
06772 if (!prev_exten) {
06773 con->root = next_node;
06774 } else {
06775 prev_exten->next = next_node;
06776 }
06777 if (peer->peer) {
06778 peer->peer->next = peer->next;
06779 }
06780 } else {
06781 previous_peer->peer = peer->peer;
06782 }
06783
06784
06785 destroy_exten(peer);
06786 } else {
06787 previous_peer = peer;
06788 }
06789 }
06790 if (!already_locked)
06791 ast_unlock_context(con);
06792 return found ? 0 : -1;
06793 }
06794
06795
06796
06797
06798
06799
06800
06801
06802 int ast_context_lockmacro(const char *context)
06803 {
06804 struct ast_context *c;
06805 int ret = -1;
06806
06807 c = find_context_locked(context);
06808 if (c) {
06809 ast_unlock_contexts();
06810
06811
06812 ret = ast_mutex_lock(&c->macrolock);
06813 }
06814
06815 return ret;
06816 }
06817
06818
06819
06820
06821
06822
06823
06824 int ast_context_unlockmacro(const char *context)
06825 {
06826 struct ast_context *c;
06827 int ret = -1;
06828
06829 c = find_context_locked(context);
06830 if (c) {
06831 ast_unlock_contexts();
06832
06833
06834 ret = ast_mutex_unlock(&c->macrolock);
06835 }
06836
06837 return ret;
06838 }
06839
06840
06841 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, const char *), const char *synopsis, const char *description, void *mod)
06842 {
06843 struct ast_app *tmp, *cur = NULL;
06844 char tmps[80];
06845 int length, res;
06846 #ifdef AST_XML_DOCS
06847 char *tmpxml;
06848 #endif
06849
06850 AST_RWLIST_WRLOCK(&apps);
06851 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
06852 if (!(res = strcasecmp(app, tmp->name))) {
06853 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
06854 AST_RWLIST_UNLOCK(&apps);
06855 return -1;
06856 } else if (res < 0)
06857 break;
06858 }
06859
06860 length = sizeof(*tmp) + strlen(app) + 1;
06861
06862 if (!(tmp = ast_calloc(1, length))) {
06863 AST_RWLIST_UNLOCK(&apps);
06864 return -1;
06865 }
06866
06867 if (ast_string_field_init(tmp, 128)) {
06868 AST_RWLIST_UNLOCK(&apps);
06869 ast_free(tmp);
06870 return -1;
06871 }
06872
06873 strcpy(tmp->name, app);
06874 tmp->execute = execute;
06875 tmp->module = mod;
06876
06877 #ifdef AST_XML_DOCS
06878
06879 if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
06880
06881 tmpxml = ast_xmldoc_build_synopsis("application", app, ast_module_name(tmp->module));
06882 ast_string_field_set(tmp, synopsis, tmpxml);
06883 ast_free(tmpxml);
06884
06885
06886 tmpxml = ast_xmldoc_build_description("application", app, ast_module_name(tmp->module));
06887 ast_string_field_set(tmp, description, tmpxml);
06888 ast_free(tmpxml);
06889
06890
06891 tmpxml = ast_xmldoc_build_syntax("application", app, ast_module_name(tmp->module));
06892 ast_string_field_set(tmp, syntax, tmpxml);
06893 ast_free(tmpxml);
06894
06895
06896 tmpxml = ast_xmldoc_build_arguments("application", app, ast_module_name(tmp->module));
06897 ast_string_field_set(tmp, arguments, tmpxml);
06898 ast_free(tmpxml);
06899
06900
06901 tmpxml = ast_xmldoc_build_seealso("application", app, ast_module_name(tmp->module));
06902 ast_string_field_set(tmp, seealso, tmpxml);
06903 ast_free(tmpxml);
06904 tmp->docsrc = AST_XML_DOC;
06905 } else {
06906 #endif
06907 ast_string_field_set(tmp, synopsis, synopsis);
06908 ast_string_field_set(tmp, description, description);
06909 #ifdef AST_XML_DOCS
06910 tmp->docsrc = AST_STATIC_DOC;
06911 }
06912 #endif
06913
06914
06915 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
06916 if (strcasecmp(tmp->name, cur->name) < 0) {
06917 AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
06918 break;
06919 }
06920 }
06921 AST_RWLIST_TRAVERSE_SAFE_END;
06922 if (!cur)
06923 AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
06924
06925 ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
06926
06927 AST_RWLIST_UNLOCK(&apps);
06928
06929 return 0;
06930 }
06931
06932
06933
06934
06935
06936 int ast_register_switch(struct ast_switch *sw)
06937 {
06938 struct ast_switch *tmp;
06939
06940 AST_RWLIST_WRLOCK(&switches);
06941 AST_RWLIST_TRAVERSE(&switches, tmp, list) {
06942 if (!strcasecmp(tmp->name, sw->name)) {
06943 AST_RWLIST_UNLOCK(&switches);
06944 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
06945 return -1;
06946 }
06947 }
06948 AST_RWLIST_INSERT_TAIL(&switches, sw, list);
06949 AST_RWLIST_UNLOCK(&switches);
06950
06951 return 0;
06952 }
06953
06954 void ast_unregister_switch(struct ast_switch *sw)
06955 {
06956 AST_RWLIST_WRLOCK(&switches);
06957 AST_RWLIST_REMOVE(&switches, sw, list);
06958 AST_RWLIST_UNLOCK(&switches);
06959 }
06960
06961
06962
06963
06964
06965 static void print_app_docs(struct ast_app *aa, int fd)
06966 {
06967
06968 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40];
06969 char seealsotitle[40];
06970 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL;
06971 char *seealso = NULL;
06972 int syntax_size, synopsis_size, description_size, arguments_size, seealso_size;
06973
06974 snprintf(info, sizeof(info), "\n -= Info about application '%s' =- \n\n", aa->name);
06975 term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
06976
06977 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
06978 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
06979 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
06980 term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
06981 term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
06982
06983 #ifdef AST_XML_DOCS
06984 if (aa->docsrc == AST_XML_DOC) {
06985 description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
06986 arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
06987 synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
06988 seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
06989
06990 if (!synopsis || !description || !arguments || !seealso) {
06991 goto return_cleanup;
06992 }
06993 } else
06994 #endif
06995 {
06996 synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
06997 synopsis = ast_malloc(synopsis_size);
06998
06999 description_size = strlen(S_OR(aa->description, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07000 description = ast_malloc(description_size);
07001
07002 arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07003 arguments = ast_malloc(arguments_size);
07004
07005 seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07006 seealso = ast_malloc(seealso_size);
07007
07008 if (!synopsis || !description || !arguments || !seealso) {
07009 goto return_cleanup;
07010 }
07011
07012 term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
07013 term_color(description, S_OR(aa->description, "Not available"), COLOR_CYAN, 0, description_size);
07014 term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
07015 term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
07016 }
07017
07018
07019 syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
07020 if (!(syntax = ast_malloc(syntax_size))) {
07021 goto return_cleanup;
07022 }
07023 term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
07024
07025 ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
07026 infotitle, syntitle, synopsis, destitle, description,
07027 stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
07028
07029 return_cleanup:
07030 ast_free(description);
07031 ast_free(arguments);
07032 ast_free(synopsis);
07033 ast_free(seealso);
07034 ast_free(syntax);
07035 }
07036
07037
07038
07039
07040 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07041 {
07042 struct ast_app *aa;
07043 int app, no_registered_app = 1;
07044
07045 switch (cmd) {
07046 case CLI_INIT:
07047 e->command = "core show application";
07048 e->usage =
07049 "Usage: core show application <application> [<application> [<application> [...]]]\n"
07050 " Describes a particular application.\n";
07051 return NULL;
07052 case CLI_GENERATE:
07053
07054
07055
07056
07057
07058 return ast_complete_applications(a->line, a->word, a->n);
07059 }
07060
07061 if (a->argc < 4) {
07062 return CLI_SHOWUSAGE;
07063 }
07064
07065 AST_RWLIST_RDLOCK(&apps);
07066 AST_RWLIST_TRAVERSE(&apps, aa, list) {
07067
07068 for (app = 3; app < a->argc; app++) {
07069 if (strcasecmp(aa->name, a->argv[app])) {
07070 continue;
07071 }
07072
07073
07074 no_registered_app = 0;
07075
07076 print_app_docs(aa, a->fd);
07077 }
07078 }
07079 AST_RWLIST_UNLOCK(&apps);
07080
07081
07082 if (no_registered_app) {
07083 ast_cli(a->fd, "Your application(s) is (are) not registered\n");
07084 return CLI_FAILURE;
07085 }
07086
07087 return CLI_SUCCESS;
07088 }
07089
07090
07091 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07092 {
07093 struct ast_hint *hint;
07094 int num = 0;
07095 int watchers;
07096 struct ao2_iterator i;
07097
07098 switch (cmd) {
07099 case CLI_INIT:
07100 e->command = "core show hints";
07101 e->usage =
07102 "Usage: core show hints\n"
07103 " List registered hints\n";
07104 return NULL;
07105 case CLI_GENERATE:
07106 return NULL;
07107 }
07108
07109 if (ao2_container_count(hints) == 0) {
07110 ast_cli(a->fd, "There are no registered dialplan hints\n");
07111 return CLI_SUCCESS;
07112 }
07113
07114 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
07115
07116 i = ao2_iterator_init(hints, 0);
07117 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07118 ao2_lock(hint);
07119 if (!hint->exten) {
07120
07121 ao2_unlock(hint);
07122 continue;
07123 }
07124 watchers = ao2_container_count(hint->callbacks);
07125 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
07126 ast_get_extension_name(hint->exten),
07127 ast_get_context_name(ast_get_extension_context(hint->exten)),
07128 ast_get_extension_app(hint->exten),
07129 ast_extension_state2str(hint->laststate), watchers);
07130 ao2_unlock(hint);
07131 num++;
07132 }
07133 ao2_iterator_destroy(&i);
07134
07135 ast_cli(a->fd, "----------------\n");
07136 ast_cli(a->fd, "- %d hints registered\n", num);
07137 return CLI_SUCCESS;
07138 }
07139
07140
07141 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
07142 {
07143 struct ast_hint *hint;
07144 char *ret = NULL;
07145 int which = 0;
07146 int wordlen;
07147 struct ao2_iterator i;
07148
07149 if (pos != 3)
07150 return NULL;
07151
07152 wordlen = strlen(word);
07153
07154
07155 i = ao2_iterator_init(hints, 0);
07156 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07157 ao2_lock(hint);
07158 if (!hint->exten) {
07159
07160 ao2_unlock(hint);
07161 continue;
07162 }
07163 if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
07164 ret = ast_strdup(ast_get_extension_name(hint->exten));
07165 ao2_unlock(hint);
07166 ao2_ref(hint, -1);
07167 break;
07168 }
07169 ao2_unlock(hint);
07170 }
07171 ao2_iterator_destroy(&i);
07172
07173 return ret;
07174 }
07175
07176
07177 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07178 {
07179 struct ast_hint *hint;
07180 int watchers;
07181 int num = 0, extenlen;
07182 struct ao2_iterator i;
07183
07184 switch (cmd) {
07185 case CLI_INIT:
07186 e->command = "core show hint";
07187 e->usage =
07188 "Usage: core show hint <exten>\n"
07189 " List registered hint\n";
07190 return NULL;
07191 case CLI_GENERATE:
07192 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
07193 }
07194
07195 if (a->argc < 4)
07196 return CLI_SHOWUSAGE;
07197
07198 if (ao2_container_count(hints) == 0) {
07199 ast_cli(a->fd, "There are no registered dialplan hints\n");
07200 return CLI_SUCCESS;
07201 }
07202
07203 extenlen = strlen(a->argv[3]);
07204 i = ao2_iterator_init(hints, 0);
07205 for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
07206 ao2_lock(hint);
07207 if (!hint->exten) {
07208
07209 ao2_unlock(hint);
07210 continue;
07211 }
07212 if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
07213 watchers = ao2_container_count(hint->callbacks);
07214 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
07215 ast_get_extension_name(hint->exten),
07216 ast_get_context_name(ast_get_extension_context(hint->exten)),
07217 ast_get_extension_app(hint->exten),
07218 ast_extension_state2str(hint->laststate), watchers);
07219 num++;
07220 }
07221 ao2_unlock(hint);
07222 }
07223 ao2_iterator_destroy(&i);
07224 if (!num)
07225 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
07226 else
07227 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->