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