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: 243489 $")
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",
02692 S_OR(acf->name, ""),
02693 S_OR(acf->syntax, ""),
02694 S_OR(acf->synopsis, ""));
02695 }
02696 }
02697 AST_RWLIST_UNLOCK(&acf_root);
02698
02699 ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
02700
02701 return CLI_SUCCESS;
02702 }
02703
02704 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02705 {
02706 struct ast_custom_function *acf;
02707
02708 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02709 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02710 char stxtitle[40], *syntax = NULL;
02711 int synopsis_size, description_size, syntax_size;
02712 char *ret = NULL;
02713 int which = 0;
02714 int wordlen;
02715
02716 switch (cmd) {
02717 case CLI_INIT:
02718 e->command = "core show function";
02719 e->usage =
02720 "Usage: core show function <function>\n"
02721 " Describe a particular dialplan function.\n";
02722 return NULL;
02723 case CLI_GENERATE:
02724 wordlen = strlen(a->word);
02725
02726 AST_RWLIST_RDLOCK(&acf_root);
02727 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02728 if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
02729 ret = ast_strdup(acf->name);
02730 break;
02731 }
02732 }
02733 AST_RWLIST_UNLOCK(&acf_root);
02734
02735 return ret;
02736 }
02737
02738 if (a->argc < 4)
02739 return CLI_SHOWUSAGE;
02740
02741 if (!(acf = ast_custom_function_find(a->argv[3]))) {
02742 ast_cli(a->fd, "No function by that name registered.\n");
02743 return CLI_FAILURE;
02744
02745 }
02746
02747 if (acf->synopsis)
02748 synopsis_size = strlen(acf->synopsis) + 23;
02749 else
02750 synopsis_size = strlen("Not available") + 23;
02751 synopsis = alloca(synopsis_size);
02752
02753 if (acf->desc)
02754 description_size = strlen(acf->desc) + 23;
02755 else
02756 description_size = strlen("Not available") + 23;
02757 description = alloca(description_size);
02758
02759 if (acf->syntax)
02760 syntax_size = strlen(acf->syntax) + 23;
02761 else
02762 syntax_size = strlen("Not available") + 23;
02763 syntax = alloca(syntax_size);
02764
02765 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
02766 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02767 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
02768 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
02769 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
02770 term_color(syntax,
02771 acf->syntax ? acf->syntax : "Not available",
02772 COLOR_CYAN, 0, syntax_size);
02773 term_color(synopsis,
02774 acf->synopsis ? acf->synopsis : "Not available",
02775 COLOR_CYAN, 0, synopsis_size);
02776 term_color(description,
02777 acf->desc ? acf->desc : "Not available",
02778 COLOR_CYAN, 0, description_size);
02779
02780 ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
02781
02782 return CLI_SUCCESS;
02783 }
02784
02785 struct ast_custom_function *ast_custom_function_find(const char *name)
02786 {
02787 struct ast_custom_function *acf = NULL;
02788
02789 AST_RWLIST_RDLOCK(&acf_root);
02790 AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02791 if (!strcmp(name, acf->name))
02792 break;
02793 }
02794 AST_RWLIST_UNLOCK(&acf_root);
02795
02796 return acf;
02797 }
02798
02799 int ast_custom_function_unregister(struct ast_custom_function *acf)
02800 {
02801 struct ast_custom_function *cur;
02802
02803 if (!acf)
02804 return -1;
02805
02806 AST_RWLIST_WRLOCK(&acf_root);
02807 if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
02808 ast_verb(2, "Unregistered custom function %s\n", cur->name);
02809 AST_RWLIST_UNLOCK(&acf_root);
02810
02811 return cur ? 0 : -1;
02812 }
02813
02814 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
02815 {
02816 struct ast_custom_function *cur;
02817 char tmps[80];
02818
02819 if (!acf)
02820 return -1;
02821
02822 acf->mod = mod;
02823
02824 AST_RWLIST_WRLOCK(&acf_root);
02825
02826 AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
02827 if (!strcmp(acf->name, cur->name)) {
02828 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
02829 AST_RWLIST_UNLOCK(&acf_root);
02830 return -1;
02831 }
02832 }
02833
02834
02835 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
02836 if (strcasecmp(acf->name, cur->name) < 0) {
02837 AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
02838 break;
02839 }
02840 }
02841 AST_RWLIST_TRAVERSE_SAFE_END;
02842 if (!cur)
02843 AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
02844
02845 AST_RWLIST_UNLOCK(&acf_root);
02846
02847 ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02848
02849 return 0;
02850 }
02851
02852
02853
02854
02855 static char *func_args(char *function)
02856 {
02857 char *args = strchr(function, '(');
02858
02859 if (!args)
02860 ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses. Assuming null argument.\n", function);
02861 else {
02862 char *p;
02863 *args++ = '\0';
02864 if ((p = strrchr(args, ')')) )
02865 *p = '\0';
02866 else
02867 ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
02868 }
02869 return args;
02870 }
02871
02872 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
02873 {
02874 char *copy = ast_strdupa(function);
02875 char *args = func_args(copy);
02876 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02877
02878 if (acfptr == NULL)
02879 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02880 else if (!acfptr->read)
02881 ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
02882 else {
02883 int res;
02884 struct ast_module_user *u = NULL;
02885 if (acfptr->mod)
02886 u = __ast_module_user_add(acfptr->mod, chan);
02887 res = acfptr->read(chan, copy, args, workspace, len);
02888 if (acfptr->mod && u)
02889 __ast_module_user_remove(acfptr->mod, u);
02890 return res;
02891 }
02892 return -1;
02893 }
02894
02895 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
02896 {
02897 char *copy = ast_strdupa(function);
02898 char *args = func_args(copy);
02899 struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02900
02901 if (acfptr == NULL)
02902 ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02903 else if (!acfptr->write)
02904 ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
02905 else {
02906 int res;
02907 struct ast_module_user *u = NULL;
02908 if (acfptr->mod)
02909 u = __ast_module_user_add(acfptr->mod, chan);
02910 res = acfptr->write(chan, copy, args, value);
02911 if (acfptr->mod && u)
02912 __ast_module_user_remove(acfptr->mod, u);
02913 return res;
02914 }
02915
02916 return -1;
02917 }
02918
02919 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
02920 {
02921
02922 char *cp4;
02923 const char *tmp, *whereweare;
02924 int length, offset, offset2, isfunction;
02925 char *workspace = NULL;
02926 char *ltmp = NULL, *var = NULL;
02927 char *nextvar, *nextexp, *nextthing;
02928 char *vars, *vare;
02929 int pos, brackets, needsub, len;
02930
02931 *cp2 = 0;
02932 whereweare=tmp=cp1;
02933 while (!ast_strlen_zero(whereweare) && count) {
02934
02935 pos = strlen(whereweare);
02936 nextvar = NULL;
02937 nextexp = NULL;
02938 nextthing = strchr(whereweare, '$');
02939 if (nextthing) {
02940 switch (nextthing[1]) {
02941 case '{':
02942 nextvar = nextthing;
02943 pos = nextvar - whereweare;
02944 break;
02945 case '[':
02946 nextexp = nextthing;
02947 pos = nextexp - whereweare;
02948 break;
02949 default:
02950 pos = 1;
02951 }
02952 }
02953
02954 if (pos) {
02955
02956 if (pos > count)
02957 pos = count;
02958
02959
02960 memcpy(cp2, whereweare, pos);
02961
02962 count -= pos;
02963 cp2 += pos;
02964 whereweare += pos;
02965 *cp2 = 0;
02966 }
02967
02968 if (nextvar) {
02969
02970
02971
02972 vars = vare = nextvar + 2;
02973 brackets = 1;
02974 needsub = 0;
02975
02976
02977 while (brackets && *vare) {
02978 if ((vare[0] == '$') && (vare[1] == '{')) {
02979 needsub++;
02980 } else if (vare[0] == '{') {
02981 brackets++;
02982 } else if (vare[0] == '}') {
02983 brackets--;
02984 } else if ((vare[0] == '$') && (vare[1] == '['))
02985 needsub++;
02986 vare++;
02987 }
02988 if (brackets)
02989 ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
02990 len = vare - vars - 1;
02991
02992
02993 whereweare += (len + 3);
02994
02995 if (!var)
02996 var = alloca(VAR_BUF_SIZE);
02997
02998
02999 ast_copy_string(var, vars, len + 1);
03000
03001
03002 if (needsub) {
03003 if (!ltmp)
03004 ltmp = alloca(VAR_BUF_SIZE);
03005
03006 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03007 vars = ltmp;
03008 } else {
03009 vars = var;
03010 }
03011
03012 if (!workspace)
03013 workspace = alloca(VAR_BUF_SIZE);
03014
03015 workspace[0] = '\0';
03016
03017 parse_variable_name(vars, &offset, &offset2, &isfunction);
03018 if (isfunction) {
03019
03020 if (c || !headp)
03021 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03022 else {
03023 struct varshead old;
03024 struct ast_channel *bogus = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
03025 if (bogus) {
03026 memcpy(&old, &bogus->varshead, sizeof(old));
03027 memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
03028 cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03029
03030 memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
03031 ast_channel_free(bogus);
03032 } else
03033 ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution. Function results may be blank.\n");
03034 }
03035 ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
03036 } else {
03037
03038 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
03039 }
03040 if (cp4) {
03041 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
03042
03043 length = strlen(cp4);
03044 if (length > count)
03045 length = count;
03046 memcpy(cp2, cp4, length);
03047 count -= length;
03048 cp2 += length;
03049 *cp2 = 0;
03050 }
03051 } else if (nextexp) {
03052
03053
03054
03055 vars = vare = nextexp + 2;
03056 brackets = 1;
03057 needsub = 0;
03058
03059
03060 while (brackets && *vare) {
03061 if ((vare[0] == '$') && (vare[1] == '[')) {
03062 needsub++;
03063 brackets++;
03064 vare++;
03065 } else if (vare[0] == '[') {
03066 brackets++;
03067 } else if (vare[0] == ']') {
03068 brackets--;
03069 } else if ((vare[0] == '$') && (vare[1] == '{')) {
03070 needsub++;
03071 vare++;
03072 }
03073 vare++;
03074 }
03075 if (brackets)
03076 ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
03077 len = vare - vars - 1;
03078
03079
03080 whereweare += (len + 3);
03081
03082 if (!var)
03083 var = alloca(VAR_BUF_SIZE);
03084
03085
03086 ast_copy_string(var, vars, len + 1);
03087
03088
03089 if (needsub) {
03090 if (!ltmp)
03091 ltmp = alloca(VAR_BUF_SIZE);
03092
03093 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03094 vars = ltmp;
03095 } else {
03096 vars = var;
03097 }
03098
03099 length = ast_expr(vars, cp2, count, c);
03100
03101 if (length) {
03102 ast_debug(1, "Expression result is '%s'\n", cp2);
03103 count -= length;
03104 cp2 += length;
03105 *cp2 = 0;
03106 }
03107 }
03108 }
03109 }
03110
03111 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
03112 {
03113 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
03114 }
03115
03116 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
03117 {
03118 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
03119 }
03120
03121 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
03122 {
03123 const char *tmp;
03124
03125
03126 if (!e->data) {
03127 *passdata = '\0';
03128 return;
03129 }
03130
03131
03132 if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03133 ast_copy_string(passdata, e->data, datalen);
03134 return;
03135 }
03136
03137 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03138 }
03139
03140
03141
03142
03143
03144
03145
03146
03147
03148
03149
03150
03151
03152
03153
03154
03155
03156
03157
03158 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
03159 const char *context, const char *exten, int priority,
03160 const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
03161 {
03162 struct ast_exten *e;
03163 struct ast_app *app;
03164 int res;
03165 struct pbx_find_info q = { .stacklen = 0 };
03166 char passdata[EXT_DATA_SIZE];
03167
03168 int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
03169
03170 ast_rdlock_contexts();
03171 if (found)
03172 *found = 0;
03173
03174 e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
03175 if (e) {
03176 if (found)
03177 *found = 1;
03178 if (matching_action) {
03179 ast_unlock_contexts();
03180 return -1;
03181 } else if (action == E_FINDLABEL) {
03182 res = e->priority;
03183 ast_unlock_contexts();
03184 return res;
03185 } else {
03186 if (!e->cached_app)
03187 e->cached_app = pbx_findapp(e->app);
03188 app = e->cached_app;
03189 ast_unlock_contexts();
03190 if (!app) {
03191 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
03192 return -1;
03193 }
03194 if (c->context != context)
03195 ast_copy_string(c->context, context, sizeof(c->context));
03196 if (c->exten != exten)
03197 ast_copy_string(c->exten, exten, sizeof(c->exten));
03198 c->priority = priority;
03199 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
03200 #ifdef CHANNEL_TRACE
03201 ast_channel_trace_update(c);
03202 #endif
03203 ast_debug(1, "Launching '%s'\n", app->name);
03204 if (VERBOSITY_ATLEAST(3)) {
03205 char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
03206 ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
03207 exten, context, priority,
03208 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
03209 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
03210 term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
03211 "in new stack");
03212 }
03213 manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
03214 "Channel: %s\r\n"
03215 "Context: %s\r\n"
03216 "Extension: %s\r\n"
03217 "Priority: %d\r\n"
03218 "Application: %s\r\n"
03219 "AppData: %s\r\n"
03220 "Uniqueid: %s\r\n",
03221 c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
03222 return pbx_exec(c, app, passdata);
03223 }
03224 } else if (q.swo) {
03225 if (found)
03226 *found = 1;
03227 ast_unlock_contexts();
03228 if (matching_action) {
03229 return -1;
03230 } else {
03231 if (!q.swo->exec) {
03232 ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
03233 res = -1;
03234 }
03235 return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
03236 }
03237 } else {
03238 ast_unlock_contexts();
03239
03240 switch (q.status) {
03241 case STATUS_NO_CONTEXT:
03242 if (!matching_action && !combined_find_spawn)
03243 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
03244 break;
03245 case STATUS_NO_EXTENSION:
03246 if (!matching_action && !combined_find_spawn)
03247 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
03248 break;
03249 case STATUS_NO_PRIORITY:
03250 if (!matching_action && !combined_find_spawn)
03251 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
03252 break;
03253 case STATUS_NO_LABEL:
03254 if (context && !combined_find_spawn)
03255 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
03256 break;
03257 default:
03258 ast_debug(1, "Shouldn't happen!\n");
03259 }
03260
03261 return (matching_action) ? 0 : -1;
03262 }
03263 }
03264
03265
03266 static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
03267 {
03268 struct pbx_find_info q = { .stacklen = 0 };
03269 return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03270 }
03271
03272 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
03273 {
03274 struct ast_exten *e;
03275 ast_rdlock_contexts();
03276 e = ast_hint_extension_nolock(c, context, exten);
03277 ast_unlock_contexts();
03278 return e;
03279 }
03280
03281 enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
03282 {
03283 switch (devstate) {
03284 case AST_DEVICE_ONHOLD:
03285 return AST_EXTENSION_ONHOLD;
03286 case AST_DEVICE_BUSY:
03287 return AST_EXTENSION_BUSY;
03288 case AST_DEVICE_UNAVAILABLE:
03289 case AST_DEVICE_UNKNOWN:
03290 case AST_DEVICE_INVALID:
03291 return AST_EXTENSION_UNAVAILABLE;
03292 case AST_DEVICE_RINGINUSE:
03293 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03294 case AST_DEVICE_RINGING:
03295 return AST_EXTENSION_RINGING;
03296 case AST_DEVICE_INUSE:
03297 return AST_EXTENSION_INUSE;
03298 case AST_DEVICE_NOT_INUSE:
03299 return AST_EXTENSION_NOT_INUSE;
03300 case AST_DEVICE_TOTAL:
03301 break;
03302 }
03303
03304 return AST_EXTENSION_NOT_INUSE;
03305 }
03306
03307
03308 static int ast_extension_state2(struct ast_exten *e)
03309 {
03310 char hint[AST_MAX_EXTENSION] = "";
03311 char *cur, *rest;
03312 struct ast_devstate_aggregate agg;
03313
03314 if (!e)
03315 return -1;
03316
03317 ast_devstate_aggregate_init(&agg);
03318
03319 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
03320
03321 rest = hint;
03322
03323 while ( (cur = strsep(&rest, "&")) ) {
03324 ast_devstate_aggregate_add(&agg, ast_device_state(cur));
03325 }
03326
03327 return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
03328 }
03329
03330
03331 const char *ast_extension_state2str(int extension_state)
03332 {
03333 int i;
03334
03335 for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03336 if (extension_states[i].extension_state == extension_state)
03337 return extension_states[i].text;
03338 }
03339 return "Unknown";
03340 }
03341
03342
03343 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
03344 {
03345 struct ast_exten *e;
03346
03347 e = ast_hint_extension(c, context, exten);
03348 if (!e)
03349 return -1;
03350
03351 return ast_extension_state2(e);
03352 }
03353
03354 static int handle_statechange(void *datap)
03355 {
03356 struct ast_hint *hint;
03357 struct statechange *sc = datap;
03358
03359 ast_rdlock_contexts();
03360 AST_RWLIST_RDLOCK(&hints);
03361
03362 AST_RWLIST_TRAVERSE(&hints, hint, list) {
03363 struct ast_state_cb *cblist;
03364 char buf[AST_MAX_EXTENSION];
03365 char *parse = buf;
03366 char *cur;
03367 int state;
03368
03369 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
03370 while ( (cur = strsep(&parse, "&")) ) {
03371 if (!strcasecmp(cur, sc->dev))
03372 break;
03373 }
03374 if (!cur)
03375 continue;
03376
03377
03378 state = ast_extension_state2(hint->exten);
03379
03380 if ((state == -1) || (state == hint->laststate))
03381 continue;
03382
03383
03384
03385
03386 AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03387 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03388 }
03389
03390
03391 AST_LIST_TRAVERSE(&hint->callbacks, cblist, entry) {
03392 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03393 }
03394
03395 hint->laststate = state;
03396 }
03397 AST_RWLIST_UNLOCK(&hints);
03398 ast_unlock_contexts();
03399 ast_free(sc);
03400 return 0;
03401 }
03402
03403
03404 int ast_extension_state_add(const char *context, const char *exten,
03405 ast_state_cb_type callback, void *data)
03406 {
03407 struct ast_hint *hint;
03408 struct ast_state_cb *cblist;
03409 struct ast_exten *e;
03410
03411
03412 if (!context && !exten) {
03413 AST_RWLIST_WRLOCK(&hints);
03414
03415 AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03416 if (cblist->callback == callback) {
03417 cblist->data = data;
03418 AST_RWLIST_UNLOCK(&hints);
03419 return 0;
03420 }
03421 }
03422
03423
03424 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03425 AST_RWLIST_UNLOCK(&hints);
03426 return -1;
03427 }
03428 cblist->id = 0;
03429 cblist->callback = callback;
03430 cblist->data = data;
03431
03432 AST_LIST_INSERT_HEAD(&statecbs, cblist, entry);
03433
03434 AST_RWLIST_UNLOCK(&hints);
03435
03436 return 0;
03437 }
03438
03439 if (!context || !exten)
03440 return -1;
03441
03442
03443 e = ast_hint_extension(NULL, context, exten);
03444 if (!e) {
03445 return -1;
03446 }
03447
03448
03449
03450
03451
03452 if (e->exten[0] == '_') {
03453 ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
03454 e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
03455 e->registrar);
03456 e = ast_hint_extension(NULL, context, exten);
03457 if (!e || e->exten[0] == '_') {
03458 return -1;
03459 }
03460 }
03461
03462
03463 AST_RWLIST_WRLOCK(&hints);
03464
03465 AST_RWLIST_TRAVERSE(&hints, hint, list) {
03466 if (hint->exten == e)
03467 break;
03468 }
03469
03470 if (!hint) {
03471
03472 AST_RWLIST_UNLOCK(&hints);
03473 return -1;
03474 }
03475
03476
03477 if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03478 AST_RWLIST_UNLOCK(&hints);
03479 return -1;
03480 }
03481
03482 cblist->id = stateid++;
03483 cblist->callback = callback;
03484 cblist->data = data;
03485
03486 AST_LIST_INSERT_HEAD(&hint->callbacks, cblist, entry);
03487
03488 AST_RWLIST_UNLOCK(&hints);
03489
03490 return cblist->id;
03491 }
03492
03493
03494 int ast_extension_state_del(int id, ast_state_cb_type callback)
03495 {
03496 struct ast_state_cb *p_cur = NULL;
03497 int ret = -1;
03498
03499 if (!id && !callback)
03500 return -1;
03501
03502 AST_RWLIST_WRLOCK(&hints);
03503
03504 if (!id) {
03505 AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) {
03506 if (p_cur->callback == callback) {
03507 AST_LIST_REMOVE_CURRENT(entry);
03508 break;
03509 }
03510 }
03511 AST_LIST_TRAVERSE_SAFE_END;
03512 } else {
03513 struct ast_hint *hint;
03514 AST_RWLIST_TRAVERSE(&hints, hint, list) {
03515 AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) {
03516 if (p_cur->id == id) {
03517 AST_LIST_REMOVE_CURRENT(entry);
03518 break;
03519 }
03520 }
03521 AST_LIST_TRAVERSE_SAFE_END;
03522
03523 if (p_cur)
03524 break;
03525 }
03526 }
03527
03528 if (p_cur) {
03529 ast_free(p_cur);
03530 }
03531
03532 AST_RWLIST_UNLOCK(&hints);
03533
03534 return ret;
03535 }
03536
03537
03538
03539 static int ast_add_hint_nolock(struct ast_exten *e)
03540 {
03541 struct ast_hint *hint;
03542
03543 if (!e)
03544 return -1;
03545
03546
03547 AST_RWLIST_TRAVERSE(&hints, hint, list) {
03548 if (hint->exten == e) {
03549 ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03550 return -1;
03551 }
03552 }
03553
03554 ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03555
03556 if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03557 return -1;
03558 }
03559
03560 hint->exten = e;
03561 hint->laststate = ast_extension_state2(e);
03562 AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03563
03564 return 0;
03565 }
03566
03567
03568 static int ast_add_hint(struct ast_exten *e)
03569 {
03570 int ret;
03571
03572 AST_RWLIST_WRLOCK(&hints);
03573 ret = ast_add_hint_nolock(e);
03574 AST_RWLIST_UNLOCK(&hints);
03575
03576 return ret;
03577 }
03578
03579
03580 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
03581 {
03582 struct ast_hint *hint;
03583 int res = -1;
03584
03585 AST_RWLIST_WRLOCK(&hints);
03586 AST_RWLIST_TRAVERSE(&hints, hint, list) {
03587 if (hint->exten == oe) {
03588 hint->exten = ne;
03589 res = 0;
03590 break;
03591 }
03592 }
03593 AST_RWLIST_UNLOCK(&hints);
03594
03595 return res;
03596 }
03597
03598
03599 static int ast_remove_hint(struct ast_exten *e)
03600 {
03601
03602 struct ast_hint *hint;
03603 struct ast_state_cb *cblist;
03604 int res = -1;
03605
03606 if (!e)
03607 return -1;
03608
03609 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
03610 if (hint->exten != e)
03611 continue;
03612
03613 while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) {
03614
03615 cblist->callback(hint->exten->parent->name, hint->exten->exten,
03616 AST_EXTENSION_DEACTIVATED, cblist->data);
03617 ast_free(cblist);
03618 }
03619
03620 AST_RWLIST_REMOVE_CURRENT(list);
03621 ast_free(hint);
03622
03623 res = 0;
03624
03625 break;
03626 }
03627 AST_RWLIST_TRAVERSE_SAFE_END;
03628
03629 return res;
03630 }
03631
03632
03633
03634 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
03635 {
03636 struct ast_exten *e = ast_hint_extension(c, context, exten);
03637
03638 if (e) {
03639 if (hint)
03640 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
03641 if (name) {
03642 const char *tmp = ast_get_extension_app_data(e);
03643 if (tmp)
03644 ast_copy_string(name, tmp, namesize);
03645 }
03646 return -1;
03647 }
03648 return 0;
03649 }
03650
03651 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03652 {
03653 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
03654 }
03655
03656 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
03657 {
03658 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03659 }
03660
03661 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
03662 {
03663 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03664 }
03665
03666 int ast_canmatch_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_CANMATCH, 0, 0);
03669 }
03670
03671 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03672 {
03673 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
03674 }
03675
03676 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)
03677 {
03678 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
03679 }
03680
03681
03682 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
03683 {
03684 ast_channel_lock(c);
03685 ast_copy_string(c->exten, exten, sizeof(c->exten));
03686 c->priority = pri;
03687 ast_channel_unlock(c);
03688 }
03689
03690
03691
03692
03693
03694
03695 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
03696 {
03697 int digit;
03698
03699 buf[pos] = '\0';
03700 while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
03701
03702
03703 digit = ast_waitfordigit(c, waittime);
03704 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03705 c->_softhangup = 0;
03706 } else {
03707 if (!digit)
03708 break;
03709 if (digit < 0)
03710 return -1;
03711 if (pos < buflen - 1) {
03712 buf[pos++] = digit;
03713 buf[pos] = '\0';
03714 }
03715 waittime = c->pbx->dtimeoutms;
03716 }
03717 }
03718 return 0;
03719 }
03720
03721 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
03722 struct ast_pbx_args *args)
03723 {
03724 int found = 0;
03725 int res = 0;
03726 int autoloopflag;
03727 int error = 0;
03728
03729
03730 if (c->pbx) {
03731 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
03732
03733 ast_free(c->pbx);
03734 }
03735 if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
03736 return -1;
03737
03738 c->pbx->rtimeoutms = 10000;
03739 c->pbx->dtimeoutms = 5000;
03740
03741 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
03742 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
03743
03744
03745 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03746
03747 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);
03748
03749
03750
03751
03752 set_ext_pri(c, "s", 1);
03753 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03754
03755 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);
03756 ast_copy_string(c->context, "default", sizeof(c->context));
03757 }
03758 }
03759 if (c->cdr) {
03760
03761 ast_cdr_update(c);
03762 }
03763 for (;;) {
03764 char dst_exten[256];
03765 int pos = 0;
03766 int digit = 0;
03767 int invalid = 0;
03768 int timeout = 0;
03769
03770
03771 while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
03772 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03773 set_ext_pri(c, "T", 0);
03774
03775 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03776 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03777 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03778 pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
03779
03780 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03781 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03782 } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03783 c->_softhangup = 0;
03784 continue;
03785 } else if (ast_check_hangup(c)) {
03786 ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
03787 c->exten, c->priority);
03788 error = 1;
03789 break;
03790 }
03791 c->priority++;
03792 }
03793 if (found && res) {
03794
03795 if (strchr("0123456789ABCDEF*#", res)) {
03796 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
03797 pos = 0;
03798 dst_exten[pos++] = digit = res;
03799 dst_exten[pos] = '\0';
03800 } else if (res == AST_PBX_INCOMPLETE) {
03801 ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03802 ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03803
03804
03805 if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03806 invalid = 1;
03807 } else {
03808 ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
03809 digit = 1;
03810 pos = strlen(dst_exten);
03811 }
03812 } else {
03813 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03814 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03815
03816 if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03817
03818 if (!strcmp(c->exten, "e")) {
03819 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);
03820 error = 1;
03821 } else {
03822 pbx_builtin_raise_exception(c, "ERROR");
03823 continue;
03824 }
03825 }
03826
03827 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03828 c->_softhangup = 0;
03829 continue;
03830 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03831 set_ext_pri(c, "T", 1);
03832
03833 memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03834 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03835 continue;
03836 } else {
03837 if (c->cdr)
03838 ast_cdr_update(c);
03839 error = 1;
03840 break;
03841 }
03842 }
03843 }
03844 if (error)
03845 break;
03846
03847
03848
03849
03850
03851
03852 if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03853
03854
03855
03856
03857
03858 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03859 ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
03860 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
03861 set_ext_pri(c, "i", 1);
03862 } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03863 pbx_builtin_raise_exception(c, "INVALID");
03864 } else {
03865 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
03866 c->name, c->exten, c->context);
03867 error = 1;
03868 break;
03869 }
03870 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
03871
03872 c->_softhangup = 0;
03873 } else {
03874 int waittime = 0;
03875 if (digit)
03876 waittime = c->pbx->dtimeoutms;
03877 else if (!autofallthrough)
03878 waittime = c->pbx->rtimeoutms;
03879 if (!waittime) {
03880 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
03881 if (!status)
03882 status = "UNKNOWN";
03883 ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
03884 if (!strcasecmp(status, "CONGESTION"))
03885 res = pbx_builtin_congestion(c, "10");
03886 else if (!strcasecmp(status, "CHANUNAVAIL"))
03887 res = pbx_builtin_congestion(c, "10");
03888 else if (!strcasecmp(status, "BUSY"))
03889 res = pbx_builtin_busy(c, "10");
03890 error = 1;
03891 break;
03892 }
03893
03894 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
03895 break;
03896 if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
03897 timeout = 1;
03898 if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num))
03899 set_ext_pri(c, dst_exten, 1);
03900 else {
03901
03902 if (!timeout && !ast_strlen_zero(dst_exten)) {
03903
03904 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03905 ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
03906 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
03907 set_ext_pri(c, "i", 1);
03908 } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03909 pbx_builtin_raise_exception(c, "INVALID");
03910 } else {
03911 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
03912 found = 1;
03913 break;
03914 }
03915 } else {
03916
03917 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
03918 ast_verb(3, "Timeout on %s\n", c->name);
03919 set_ext_pri(c, "t", 1);
03920 } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03921 pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
03922 } else {
03923 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
03924 found = 1;
03925 break;
03926 }
03927 }
03928 }
03929 if (c->cdr) {
03930 ast_verb(2, "CDR updated on %s\n",c->name);
03931 ast_cdr_update(c);
03932 }
03933 }
03934 }
03935
03936 if (!found && !error) {
03937 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
03938 }
03939
03940 if (!args || !args->no_hangup_chan) {
03941 ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
03942 }
03943
03944 if ((!args || !args->no_hangup_chan) &&
03945 !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) &&
03946 ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
03947 set_ext_pri(c, "h", 1);
03948 if (c->cdr && ast_opt_end_cdr_before_h_exten) {
03949 ast_cdr_end(c->cdr);
03950 }
03951 while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
03952 c->priority++;
03953 }
03954 if (found && res) {
03955
03956 ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03957 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03958 }
03959 }
03960 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03961 ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN);
03962 pbx_destroy(c->pbx);
03963 c->pbx = NULL;
03964
03965 if (!args || !args->no_hangup_chan) {
03966 ast_hangup(c);
03967 }
03968
03969 return 0;
03970 }
03971
03972
03973
03974
03975
03976
03977 static int increase_call_count(const struct ast_channel *c)
03978 {
03979 int failed = 0;
03980 double curloadavg;
03981 #if defined(HAVE_SYSINFO)
03982 long curfreemem;
03983 struct sysinfo sys_info;
03984 #endif
03985
03986 ast_mutex_lock(&maxcalllock);
03987 if (option_maxcalls) {
03988 if (countcalls >= option_maxcalls) {
03989 ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
03990 failed = -1;
03991 }
03992 }
03993 if (option_maxload) {
03994 getloadavg(&curloadavg, 1);
03995 if (curloadavg >= option_maxload) {
03996 ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
03997 failed = -1;
03998 }
03999 }
04000 #if defined(HAVE_SYSINFO)
04001 if (option_minmemfree) {
04002 if (!sysinfo(&sys_info)) {
04003
04004
04005 curfreemem = sys_info.freeram / sys_info.mem_unit;
04006 curfreemem /= 1024*1024;
04007 if (curfreemem < option_minmemfree) {
04008 ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
04009 failed = -1;
04010 }
04011 }
04012 }
04013 #endif
04014
04015 if (!failed) {
04016 countcalls++;
04017 totalcalls++;
04018 }
04019 ast_mutex_unlock(&maxcalllock);
04020
04021 return failed;
04022 }
04023
04024 static void decrease_call_count(void)
04025 {
04026 ast_mutex_lock(&maxcalllock);
04027 if (countcalls > 0)
04028 countcalls--;
04029 ast_mutex_unlock(&maxcalllock);
04030 }
04031
04032 static void destroy_exten(struct ast_exten *e)
04033 {
04034 if (e->priority == PRIORITY_HINT)
04035 ast_remove_hint(e);
04036
04037 if (e->peer_table)
04038 ast_hashtab_destroy(e->peer_table,0);
04039 if (e->peer_label_table)
04040 ast_hashtab_destroy(e->peer_label_table, 0);
04041 if (e->datad)
04042 e->datad(e->data);
04043 ast_free(e);
04044 }
04045
04046 static void *pbx_thread(void *data)
04047 {
04048
04049
04050
04051
04052
04053
04054
04055
04056 struct ast_channel *c = data;
04057
04058 __ast_pbx_run(c, NULL);
04059 decrease_call_count();
04060
04061 pthread_exit(NULL);
04062
04063 return NULL;
04064 }
04065
04066 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
04067 {
04068 pthread_t t;
04069
04070 if (!c) {
04071 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04072 return AST_PBX_FAILED;
04073 }
04074
04075 if (increase_call_count(c))
04076 return AST_PBX_CALL_LIMIT;
04077
04078
04079 if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04080 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04081 decrease_call_count();
04082 return AST_PBX_FAILED;
04083 }
04084
04085 return AST_PBX_SUCCESS;
04086 }
04087
04088 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
04089 {
04090 enum ast_pbx_result res = AST_PBX_SUCCESS;
04091
04092 if (increase_call_count(c)) {
04093 return AST_PBX_CALL_LIMIT;
04094 }
04095
04096 res = __ast_pbx_run(c, args);
04097
04098 decrease_call_count();
04099
04100 return res;
04101 }
04102
04103 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
04104 {
04105 return ast_pbx_run_args(c, NULL);
04106 }
04107
04108 int ast_active_calls(void)
04109 {
04110 return countcalls;
04111 }
04112
04113 int ast_processed_calls(void)
04114 {
04115 return totalcalls;
04116 }
04117
04118 int pbx_set_autofallthrough(int newval)
04119 {
04120 int oldval = autofallthrough;
04121 autofallthrough = newval;
04122 return oldval;
04123 }
04124
04125 int pbx_set_extenpatternmatchnew(int newval)
04126 {
04127 int oldval = extenpatternmatchnew;
04128 extenpatternmatchnew = newval;
04129 return oldval;
04130 }
04131
04132 void pbx_set_overrideswitch(const char *newval)
04133 {
04134 if (overrideswitch) {
04135 ast_free(overrideswitch);
04136 }
04137 if (!ast_strlen_zero(newval)) {
04138 overrideswitch = ast_strdup(newval);
04139 } else {
04140 overrideswitch = NULL;
04141 }
04142 }
04143
04144
04145
04146
04147
04148 static struct ast_context *find_context(const char *context)
04149 {
04150 struct ast_context *c = NULL;
04151 struct fake_context item;
04152
04153 ast_copy_string(item.name, context, sizeof(item.name));
04154
04155 c = ast_hashtab_lookup(contexts_table,&item);
04156
04157 return c;
04158 }
04159
04160
04161
04162
04163
04164
04165 static struct ast_context *find_context_locked(const char *context)
04166 {
04167 struct ast_context *c = NULL;
04168 struct fake_context item;
04169
04170 ast_copy_string(item.name, context, sizeof(item.name));
04171
04172 ast_rdlock_contexts();
04173 c = ast_hashtab_lookup(contexts_table,&item);
04174
04175 #ifdef NOTNOW
04176
04177 while ( (c = ast_walk_contexts(c)) ) {
04178 if (!strcmp(ast_get_context_name(c), context))
04179 return c;
04180 }
04181 #endif
04182 if (!c)
04183 ast_unlock_contexts();
04184
04185 return c;
04186 }
04187
04188
04189
04190
04191
04192
04193
04194 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
04195 {
04196 int ret = -1;
04197 struct ast_context *c = find_context_locked(context);
04198
04199 if (c) {
04200
04201 ret = ast_context_remove_include2(c, include, registrar);
04202 ast_unlock_contexts();
04203 }
04204 return ret;
04205 }
04206
04207
04208
04209
04210
04211
04212
04213
04214
04215
04216 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
04217 {
04218 struct ast_include *i, *pi = NULL;
04219 int ret = -1;
04220
04221 ast_wrlock_context(con);
04222
04223
04224 for (i = con->includes; i; pi = i, i = i->next) {
04225 if (!strcmp(i->name, include) &&
04226 (!registrar || !strcmp(i->registrar, registrar))) {
04227
04228 ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04229 if (pi)
04230 pi->next = i->next;
04231 else
04232 con->includes = i->next;
04233
04234 ast_free(i);
04235 ret = 0;
04236 break;
04237 }
04238 }
04239
04240 ast_unlock_context(con);
04241
04242 return ret;
04243 }
04244
04245
04246
04247
04248
04249
04250 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
04251 {
04252 int ret = -1;
04253 struct ast_context *c = find_context_locked(context);
04254
04255 if (c) {
04256
04257 ret = ast_context_remove_switch2(c, sw, data, registrar);
04258 ast_unlock_contexts();
04259 }
04260 return ret;
04261 }
04262
04263
04264
04265
04266
04267
04268
04269
04270
04271 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
04272 {
04273 struct ast_sw *i;
04274 int ret = -1;
04275
04276 ast_wrlock_context(con);
04277
04278
04279 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04280 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04281 (!registrar || !strcmp(i->registrar, registrar))) {
04282
04283 ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04284 AST_LIST_REMOVE_CURRENT(list);
04285 ast_free(i);
04286 ret = 0;
04287 break;
04288 }
04289 }
04290 AST_LIST_TRAVERSE_SAFE_END;
04291
04292 ast_unlock_context(con);
04293
04294 return ret;
04295 }
04296
04297
04298
04299
04300
04301
04302 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
04303 {
04304 return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04305 }
04306
04307 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
04308 {
04309 int ret = -1;
04310 struct ast_context *c = find_context_locked(context);
04311
04312 if (c) {
04313 ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
04314 ast_unlock_contexts();
04315 }
04316 return ret;
04317 }
04318
04319
04320
04321
04322
04323
04324
04325
04326
04327
04328
04329 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
04330 {
04331 return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04332 }
04333
04334 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)
04335 {
04336 struct ast_exten *exten, *prev_exten = NULL;
04337 struct ast_exten *peer;
04338 struct ast_exten ex, *exten2, *exten3;
04339 char dummy_name[1024];
04340 struct ast_exten *previous_peer = NULL;
04341 struct ast_exten *next_peer = NULL;
04342 int found = 0;
04343
04344 if (!already_locked)
04345 ast_wrlock_context(con);
04346
04347
04348
04349
04350
04351 #ifdef NEED_DEBUG
04352 ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
04353 #endif
04354 #ifdef CONTEXT_DEBUG
04355 check_contexts(__FILE__, __LINE__);
04356 #endif
04357
04358 ex.exten = dummy_name;
04359 ex.matchcid = matchcallerid && !ast_strlen_zero(callerid);
04360 ex.cidmatch = callerid;
04361 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
04362 exten = ast_hashtab_lookup(con->root_table, &ex);
04363 if (exten) {
04364 if (priority == 0) {
04365 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04366 if (!exten2)
04367 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);
04368 if (con->pattern_tree) {
04369
04370 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04371
04372 if (x->exten) {
04373 x->deleted = 1;
04374 x->exten = 0;
04375 } else {
04376 ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
04377 }
04378 }
04379 } else {
04380 ex.priority = priority;
04381 exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
04382 if (exten2) {
04383
04384 if (exten2->label) {
04385 exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
04386 if (!exten3)
04387 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);
04388 }
04389
04390 exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
04391 if (!exten3)
04392 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);
04393 if (exten2 == exten && exten2->peer) {
04394 exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04395 ast_hashtab_insert_immediate(con->root_table, exten2->peer);
04396 }
04397 if (ast_hashtab_size(exten->peer_table) == 0) {
04398
04399
04400 exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
04401 if (!exten3)
04402 ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
04403 if (con->pattern_tree) {
04404 struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04405 if (x->exten) {
04406 x->deleted = 1;
04407 x->exten = 0;
04408 }
04409 }
04410 }
04411 } else {
04412 ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
04413 priority, exten->exten, con->name);
04414 }
04415 }
04416 } else {
04417
04418 ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
04419 extension, con->name);
04420 }
04421 #ifdef NEED_DEBUG
04422 if (con->pattern_tree) {
04423 ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
04424 log_match_char_tree(con->pattern_tree, " ");
04425 }
04426 #endif
04427
04428
04429 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
04430 if (!strcmp(exten->exten, extension) &&
04431 (!registrar || !strcmp(exten->registrar, registrar)) &&
04432 (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
04433 break;
04434 }
04435 if (!exten) {
04436
04437 if (!already_locked)
04438 ast_unlock_context(con);
04439 return -1;
04440 }
04441
04442
04443 for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
04444 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)));
04445 peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
04446 if ((priority == 0 || peer->priority == priority) &&
04447 (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
04448 (!registrar || !strcmp(peer->registrar, registrar) )) {
04449 found = 1;
04450
04451
04452 if (!previous_peer) {
04453
04454
04455
04456
04457 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
04458 if (peer->peer) {
04459
04460
04461 peer->peer->peer_table = peer->peer_table;
04462 peer->peer->peer_label_table = peer->peer_label_table;
04463 peer->peer_table = NULL;
04464 peer->peer_label_table = NULL;
04465 }
04466 if (!prev_exten) {
04467 con->root = next_node;
04468 } else {
04469 prev_exten->next = next_node;
04470 }
04471 if (peer->peer) {
04472 peer->peer->next = peer->next;
04473 }
04474 } else {
04475 previous_peer->peer = peer->peer;
04476 }
04477
04478
04479 destroy_exten(peer);
04480 } else {
04481 previous_peer = peer;
04482 }
04483 }
04484 if (!already_locked)
04485 ast_unlock_context(con);
04486 return found ? 0 : -1;
04487 }
04488
04489
04490
04491
04492
04493
04494
04495 int ast_context_lockmacro(const char *context)
04496 {
04497 struct ast_context *c = NULL;
04498 int ret = -1;
04499 struct fake_context item;
04500
04501 ast_rdlock_contexts();
04502
04503 ast_copy_string(item.name, context, sizeof(item.name));
04504
04505 c = ast_hashtab_lookup(contexts_table,&item);
04506 if (c)
04507 ret = 0;
04508
04509
04510 #ifdef NOTNOW
04511
04512 while ((c = ast_walk_contexts(c))) {
04513 if (!strcmp(ast_get_context_name(c), context)) {
04514 ret = 0;
04515 break;
04516 }
04517 }
04518
04519 #endif
04520 ast_unlock_contexts();
04521
04522
04523 if (ret == 0)
04524 ret = ast_mutex_lock(&c->macrolock);
04525
04526 return ret;
04527 }
04528
04529
04530
04531
04532
04533
04534 int ast_context_unlockmacro(const char *context)
04535 {
04536 struct ast_context *c = NULL;
04537 int ret = -1;
04538 struct fake_context item;
04539
04540 ast_rdlock_contexts();
04541
04542 ast_copy_string(item.name, context, sizeof(item.name));
04543
04544 c = ast_hashtab_lookup(contexts_table,&item);
04545 if (c)
04546 ret = 0;
04547 #ifdef NOTNOW
04548
04549 while ((c = ast_walk_contexts(c))) {
04550 if (!strcmp(ast_get_context_name(c), context)) {
04551 ret = 0;
04552 break;
04553 }
04554 }
04555
04556 #endif
04557 ast_unlock_contexts();
04558
04559
04560 if (ret == 0)
04561 ret = ast_mutex_unlock(&c->macrolock);
04562
04563 return ret;
04564 }
04565
04566
04567 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description, void *mod)
04568 {
04569 struct ast_app *tmp, *cur = NULL;
04570 char tmps[80];
04571 int length, res;
04572
04573 AST_RWLIST_WRLOCK(&apps);
04574 AST_RWLIST_TRAVERSE(&apps, tmp, list) {
04575 if (!(res = strcasecmp(app, tmp->name))) {
04576 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
04577 AST_RWLIST_UNLOCK(&apps);
04578 return -1;
04579 } else if (res < 0)
04580 break;
04581 }
04582
04583 length = sizeof(*tmp) + strlen(app) + 1;
04584
04585 if (!(tmp = ast_calloc(1, length))) {
04586 AST_RWLIST_UNLOCK(&apps);
04587 return -1;
04588 }
04589
04590 strcpy(tmp->name, app);
04591 tmp->execute = execute;
04592 tmp->synopsis = synopsis;
04593 tmp->description = description;
04594 tmp->module = mod;
04595
04596
04597 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
04598 if (strcasecmp(tmp->name, cur->name) < 0) {
04599 AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
04600 break;
04601 }
04602 }
04603 AST_RWLIST_TRAVERSE_SAFE_END;
04604 if (!cur)
04605 AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
04606
04607 ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
04608
04609 AST_RWLIST_UNLOCK(&apps);
04610
04611 return 0;
04612 }
04613
04614
04615
04616
04617
04618 int ast_register_switch(struct ast_switch *sw)
04619 {
04620 struct ast_switch *tmp;
04621
04622 AST_RWLIST_WRLOCK(&switches);
04623 AST_RWLIST_TRAVERSE(&switches, tmp, list) {
04624 if (!strcasecmp(tmp->name, sw->name)) {
04625 AST_RWLIST_UNLOCK(&switches);
04626 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
04627 return -1;
04628 }
04629 }
04630 AST_RWLIST_INSERT_TAIL(&switches, sw, list);
04631 AST_RWLIST_UNLOCK(&switches);
04632
04633 return 0;
04634 }
04635
04636 void ast_unregister_switch(struct ast_switch *sw)
04637 {
04638 AST_RWLIST_WRLOCK(&switches);
04639 AST_RWLIST_REMOVE(&switches, sw, list);
04640 AST_RWLIST_UNLOCK(&switches);
04641 }
04642
04643
04644
04645
04646
04647
04648
04649
04650 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04651 {
04652 struct ast_app *aa;
04653 int app, no_registered_app = 1;
04654 char *ret = NULL;
04655 int which = 0;
04656 int wordlen;
04657
04658 switch (cmd) {
04659 case CLI_INIT:
04660 e->command = "core show application";
04661 e->usage =
04662 "Usage: core show application <application> [<application> [<application> [...]]]\n"
04663 " Describes a particular application.\n";
04664 return NULL;
04665 case CLI_GENERATE:
04666
04667
04668
04669
04670
04671 wordlen = strlen(a->word);
04672
04673 AST_RWLIST_RDLOCK(&apps);
04674 AST_RWLIST_TRAVERSE(&apps, aa, list) {
04675 if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
04676 ret = ast_strdup(aa->name);
04677 break;
04678 }
04679 }
04680 AST_RWLIST_UNLOCK(&apps);
04681
04682 return ret;
04683 }
04684
04685 if (a->argc < 4)
04686 return CLI_SHOWUSAGE;
04687
04688
04689 AST_RWLIST_RDLOCK(&apps);
04690 AST_RWLIST_TRAVERSE(&apps, aa, list) {
04691
04692
04693 for (app = 3; app < a->argc; app++) {
04694 if (!strcasecmp(aa->name, a->argv[app])) {
04695
04696 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
04697 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
04698 int synopsis_size, description_size;
04699
04700 no_registered_app = 0;
04701
04702 if (aa->synopsis)
04703 synopsis_size = strlen(aa->synopsis) + 23;
04704 else
04705 synopsis_size = strlen("Not available") + 23;
04706 synopsis = alloca(synopsis_size);
04707
04708 if (aa->description)
04709 description_size = strlen(aa->description) + 23;
04710 else
04711 description_size = strlen("Not available") + 23;
04712 description = alloca(description_size);
04713
04714 if (synopsis && description) {
04715 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", aa->name);
04716 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
04717 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
04718 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
04719 term_color(synopsis,
04720 aa->synopsis ? aa->synopsis : "Not available",
04721 COLOR_CYAN, 0, synopsis_size);
04722 term_color(description,
04723 aa->description ? aa->description : "Not available",
04724 COLOR_CYAN, 0, description_size);
04725
04726 ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
04727 } else {
04728
04729 ast_cli(a->fd,"\n -= Info about application '%s' =- \n\n"
04730 "[Synopsis]\n %s\n\n"
04731 "[Description]\n%s\n",
04732 aa->name,
04733 aa->synopsis ? aa->synopsis : "Not available",
04734 aa->description ? aa->description : "Not available");
04735 }
04736 }
04737 }
04738 }
04739 AST_RWLIST_UNLOCK(&apps);
04740
04741
04742 if (no_registered_app) {
04743 ast_cli(a->fd, "Your application(s) is (are) not registered\n");
04744 return CLI_FAILURE;
04745 }
04746
04747 return CLI_SUCCESS;
04748 }
04749
04750
04751 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04752 {
04753 struct ast_hint *hint;
04754 int num = 0;
04755 int watchers;
04756 struct ast_state_cb *watcher;
04757
04758 switch (cmd) {
04759 case CLI_INIT:
04760 e->command = "core show hints";
04761 e->usage =
04762 "Usage: core show hints\n"
04763 " List registered hints\n";
04764 return NULL;
04765 case CLI_GENERATE:
04766 return NULL;
04767 }
04768
04769 AST_RWLIST_RDLOCK(&hints);
04770 if (AST_RWLIST_EMPTY(&hints)) {
04771 ast_cli(a->fd, "There are no registered dialplan hints\n");
04772 AST_RWLIST_UNLOCK(&hints);
04773 return CLI_SUCCESS;
04774 }
04775
04776 ast_cli(a->fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
04777 AST_RWLIST_TRAVERSE(&hints, hint, list) {
04778 watchers = 0;
04779 AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04780 watchers++;
04781 }
04782 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
04783 ast_get_extension_name(hint->exten),
04784 ast_get_context_name(ast_get_extension_context(hint->exten)),
04785 ast_get_extension_app(hint->exten),
04786 ast_extension_state2str(hint->laststate), watchers);
04787 num++;
04788 }
04789 ast_cli(a->fd, "----------------\n");
04790 ast_cli(a->fd, "- %d hints registered\n", num);
04791 AST_RWLIST_UNLOCK(&hints);
04792 return CLI_SUCCESS;
04793 }
04794
04795
04796 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
04797 {
04798 struct ast_hint *hint;
04799 char *ret = NULL;
04800 int which = 0;
04801 int wordlen;
04802
04803 if (pos != 3)
04804 return NULL;
04805
04806 wordlen = strlen(word);
04807
04808 AST_RWLIST_RDLOCK(&hints);
04809
04810 AST_RWLIST_TRAVERSE(&hints, hint, list) {
04811 if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
04812 ret = ast_strdup(ast_get_extension_name(hint->exten));
04813 break;
04814 }
04815 }
04816 AST_RWLIST_UNLOCK(&hints);
04817
04818 return ret;
04819 }
04820
04821
04822 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04823 {
04824 struct ast_hint *hint;
04825 int watchers;
04826 int num = 0, extenlen;
04827 struct ast_state_cb *watcher;
04828
04829 switch (cmd) {
04830 case CLI_INIT:
04831 e->command = "core show hint";
04832 e->usage =
04833 "Usage: core show hint <exten>\n"
04834 " List registered hint\n";
04835 return NULL;
04836 case CLI_GENERATE:
04837 return complete_core_show_hint(a->line, a->word, a->pos, a->n);
04838 }
04839
04840 if (a->argc < 4)
04841 return CLI_SHOWUSAGE;
04842
04843 AST_RWLIST_RDLOCK(&hints);
04844 if (AST_RWLIST_EMPTY(&hints)) {
04845 ast_cli(a->fd, "There are no registered dialplan hints\n");
04846 AST_RWLIST_UNLOCK(&hints);
04847 return CLI_SUCCESS;
04848 }
04849 extenlen = strlen(a->argv[3]);
04850 AST_RWLIST_TRAVERSE(&hints, hint, list) {
04851 if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
04852 watchers = 0;
04853 AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04854 watchers++;
04855 }
04856 ast_cli(a->fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
04857 ast_get_extension_name(hint->exten),
04858 ast_get_context_name(ast_get_extension_context(hint->exten)),
04859 ast_get_extension_app(hint->exten),
04860 ast_extension_state2str(hint->laststate), watchers);
04861 num++;
04862 }
04863 }
04864 AST_RWLIST_UNLOCK(&hints);
04865 if (!num)
04866 ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
04867 else
04868 ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
04869 return CLI_SUCCESS;
04870 }
04871
04872
04873
04874 static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04875 {
04876 struct ast_switch *sw;
04877
04878 switch (cmd) {
04879 case CLI_INIT:
04880 e->command = "core show switches";
04881 e->usage =
04882 "Usage: core show switches\n"
04883 " List registered switches\n";
04884 return NULL;
04885 case CLI_GENERATE:
04886 return NULL;
04887 }
04888
04889 AST_RWLIST_RDLOCK(&switches);
04890
04891 if (AST_RWLIST_EMPTY(&switches)) {
04892 AST_RWLIST_UNLOCK(&switches);
04893 ast_cli(a->fd, "There are no registered alternative switches\n");
04894 return CLI_SUCCESS;
04895 }
04896
04897 ast_cli(a->fd, "\n -= Registered Asterisk Alternative Switches =-\n");
04898 AST_RWLIST_TRAVERSE(&switches, sw, list)
04899 ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
04900
04901 AST_RWLIST_UNLOCK(&switches);
04902
04903 return CLI_SUCCESS;
04904 }
04905
04906 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04907 {
04908 struct ast_app *aa;
04909 int like = 0, describing = 0;
04910 int total_match = 0;
04911 int total_apps = 0;
04912 static char* choices[] = { "like", "describing", NULL };
04913
04914 switch (cmd) {
04915 case CLI_INIT:
04916 e->command = "core show applications [like|describing]";
04917 e->usage =
04918 "Usage: core show applications [{like|describing} <text>]\n"
04919 " List applications which are currently available.\n"
04920 " If 'like', <text> will be a substring of the app name\n"
04921 " If 'describing', <text> will be a substring of the description\n";
04922 return NULL;
04923 case CLI_GENERATE:
04924 return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
04925 }
04926
04927 AST_RWLIST_RDLOCK(&apps);
04928
04929 if (AST_RWLIST_EMPTY(&apps)) {
04930 ast_cli(a->fd, "There are no registered applications\n");
04931 AST_RWLIST_UNLOCK(&apps);
04932 return CLI_SUCCESS;
04933 }
04934
04935
04936 if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
04937 like = 1;
04938 } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
04939 describing = 1;
04940 }
04941
04942
04943 if ((!like) && (!describing)) {
04944 ast_cli(a->fd, " -= Registered Asterisk Applications =-\n");
04945 } else {
04946 ast_cli(a->fd, " -= Matching Asterisk Applications =-\n");
04947 }
04948
04949 AST_RWLIST_TRAVERSE(&apps, aa, list) {
04950 int printapp = 0;
04951 total_apps++;
04952 if (like) {
04953 if (strcasestr(aa->name, a->argv[4])) {
04954 printapp = 1;
04955 total_match++;
04956 }
04957 } else if (describing) {
04958 if (aa->description) {
04959
04960 int i;
04961 printapp = 1;
04962 for (i = 4; i < a->argc; i++) {
04963 if (!strcasestr(aa->description, a->argv[i])) {
04964 printapp = 0;
04965 } else {
04966 total_match++;
04967 }
04968 }
04969 }
04970 } else {
04971 printapp = 1;
04972 }
04973
04974 if (printapp) {
04975 ast_cli(a->fd," %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
04976 }
04977 }
04978 if ((!like) && (!describing)) {
04979 ast_cli(a->fd, " -= %d Applications Registered =-\n",total_apps);
04980 } else {
04981 ast_cli(a->fd, " -= %d Applications Matching =-\n",total_match);
04982 }
04983
04984 AST_RWLIST_UNLOCK(&apps);
04985
04986 return CLI_SUCCESS;
04987 }
04988
04989
04990
04991
04992 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
04993 int state)
04994 {
04995 struct ast_context *c = NULL;
04996 char *ret = NULL;
04997 int which = 0;
04998 int wordlen;
04999
05000
05001 if (pos != 2)
05002 return NULL;
05003
05004 ast_rdlock_contexts();
05005
05006 wordlen = strlen(word);
05007
05008
05009 while ( (c = ast_walk_contexts(c)) ) {
05010 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
05011 ret = ast_strdup(ast_get_context_name(c));
05012 break;
05013 }
05014 }
05015
05016 ast_unlock_contexts();
05017
05018 return ret;
05019 }
05020
05021
05022 struct dialplan_counters {
05023 int total_items;
05024 int total_context;
05025 int total_exten;
05026 int total_prio;
05027 int context_existence;
05028 int extension_existence;
05029 };
05030
05031
05032 static void print_ext(struct ast_exten *e, char * buf, int buflen)
05033 {
05034 int prio = ast_get_extension_priority(e);
05035 if (prio == PRIORITY_HINT) {
05036 snprintf(buf, buflen, "hint: %s",
05037 ast_get_extension_app(e));
05038 } else {
05039 snprintf(buf, buflen, "%d. %s(%s)",
05040 prio, ast_get_extension_app(e),
05041 (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
05042 }
05043 }
05044
05045
05046 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[])
05047 {
05048 struct ast_context *c = NULL;
05049 int res = 0, old_total_exten = dpc->total_exten;
05050
05051 ast_rdlock_contexts();
05052
05053
05054 while ( (c = ast_walk_contexts(c)) ) {
05055 struct ast_exten *e;
05056 struct ast_include *i;
05057 struct ast_ignorepat *ip;
05058 char buf[256], buf2[256];
05059 int context_info_printed = 0;
05060
05061 if (context && strcmp(ast_get_context_name(c), context))
05062 continue;
05063
05064 dpc->context_existence = 1;
05065
05066 ast_rdlock_context(c);
05067
05068
05069
05070
05071
05072
05073
05074 if (!exten) {
05075 dpc->total_context++;
05076 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05077 ast_get_context_name(c), ast_get_context_registrar(c));
05078 context_info_printed = 1;
05079 }
05080
05081
05082 e = NULL;
05083 while ( (e = ast_walk_context_extensions(c, e)) ) {
05084 struct ast_exten *p;
05085
05086 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
05087 continue;
05088
05089 dpc->extension_existence = 1;
05090
05091
05092 if (!context_info_printed) {
05093 dpc->total_context++;
05094 if (rinclude) {
05095 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
05096 ast_get_context_name(c), ast_get_context_registrar(c));
05097 } else {
05098 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05099 ast_get_context_name(c), ast_get_context_registrar(c));
05100 }
05101 context_info_printed = 1;
05102 }
05103 dpc->total_prio++;
05104
05105
05106 if (e->matchcid)
05107 snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
05108 else
05109 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
05110
05111 print_ext(e, buf2, sizeof(buf2));
05112
05113 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
05114 ast_get_extension_registrar(e));
05115
05116 dpc->total_exten++;
05117
05118 p = e;
05119 while ( (p = ast_walk_extension_priorities(e, p)) ) {
05120 const char *el = ast_get_extension_label(p);
05121 dpc->total_prio++;
05122 if (el)
05123 snprintf(buf, sizeof(buf), " [%s]", el);
05124 else
05125 buf[0] = '\0';
05126 print_ext(p, buf2, sizeof(buf2));
05127
05128 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
05129 ast_get_extension_registrar(p));
05130 }
05131 }
05132
05133
05134 i = NULL;
05135 while ( (i = ast_walk_context_includes(c, i)) ) {
05136 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
05137 if (exten) {
05138
05139 if (includecount >= AST_PBX_MAX_STACK) {
05140 ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
05141 } else {
05142 int dupe = 0;
05143 int x;
05144 for (x = 0; x < includecount; x++) {
05145 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
05146 dupe++;
05147 break;
05148 }
05149 }
05150 if (!dupe) {
05151 includes[includecount] = ast_get_include_name(i);
05152 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
05153 } else {
05154 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
05155 }
05156 }
05157 } else {
05158 ast_cli(fd, " Include => %-45s [%s]\n",
05159 buf, ast_get_include_registrar(i));
05160 }
05161 }
05162
05163
05164 ip = NULL;
05165 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05166 const char *ipname = ast_get_ignorepat_name(ip);
05167 char ignorepat[AST_MAX_EXTENSION];
05168 snprintf(buf, sizeof(buf), "'%s'", ipname);
05169 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05170 if (!exten || ast_extension_match(ignorepat, exten)) {
05171 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
05172 buf, ast_get_ignorepat_registrar(ip));
05173 }
05174 }
05175 if (!rinclude) {
05176 struct ast_sw *sw = NULL;
05177 while ( (sw = ast_walk_context_switches(c, sw)) ) {
05178 snprintf(buf, sizeof(buf), "'%s/%s'",
05179 ast_get_switch_name(sw),
05180 ast_get_switch_data(sw));
05181 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
05182 buf, ast_get_switch_registrar(sw));
05183 }
05184 }
05185
05186 ast_unlock_context(c);
05187
05188
05189 if (context_info_printed)
05190 ast_cli(fd, "\n");
05191 }
05192 ast_unlock_contexts();
05193
05194 return (dpc->total_exten == old_total_exten) ? -1 : res;
05195 }
05196
05197 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[])
05198 {
05199 struct ast_context *c = NULL;
05200 int res = 0, old_total_exten = dpc->total_exten;
05201
05202 ast_cli(fd,"\n In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
05203
05204 ast_cli(fd,"\n Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
05205 ast_cli(fd, " Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
05206 ast_cli(fd, " <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
05207 ast_cli(fd, " <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
05208 ast_cli(fd, " [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
05209 ast_cli(fd, " In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
05210 ast_cli(fd, " are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
05211 ast_rdlock_contexts();
05212
05213
05214 while ( (c = ast_walk_contexts(c)) ) {
05215 int context_info_printed = 0;
05216
05217 if (context && strcmp(ast_get_context_name(c), context))
05218 continue;
05219
05220 dpc->context_existence = 1;
05221
05222 if (!c->pattern_tree)
05223 ast_exists_extension(NULL, c->name, "s", 1, "");
05224
05225 ast_rdlock_context(c);
05226
05227 dpc->total_context++;
05228 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05229 ast_get_context_name(c), ast_get_context_registrar(c));
05230 context_info_printed = 1;
05231
05232 if (c->pattern_tree)
05233 {
05234 cli_match_char_tree(c->pattern_tree, " ", fd);
05235 } else {
05236 ast_cli(fd,"\n No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
05237 }
05238
05239 ast_unlock_context(c);
05240
05241
05242 if (context_info_printed)
05243 ast_cli(fd, "\n");
05244 }
05245 ast_unlock_contexts();
05246
05247 return (dpc->total_exten == old_total_exten) ? -1 : res;
05248 }
05249
05250 static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05251 {
05252 char *exten = NULL, *context = NULL;
05253
05254 struct dialplan_counters counters;
05255 const char *incstack[AST_PBX_MAX_STACK];
05256
05257 switch (cmd) {
05258 case CLI_INIT:
05259 e->command = "dialplan show";
05260 e->usage =
05261 "Usage: dialplan show [[exten@]context]\n"
05262 " Show dialplan\n";
05263 return NULL;
05264 case CLI_GENERATE:
05265 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05266 }
05267
05268 memset(&counters, 0, sizeof(counters));
05269
05270 if (a->argc != 2 && a->argc != 3)
05271 return CLI_SHOWUSAGE;
05272
05273
05274 if (a->argc == 3) {
05275 if (strchr(a->argv[2], '@')) {
05276 context = ast_strdupa(a->argv[2]);
05277 exten = strsep(&context, "@");
05278
05279 if (ast_strlen_zero(exten))
05280 exten = NULL;
05281 } else {
05282 context = a->argv[2];
05283 }
05284 if (ast_strlen_zero(context))
05285 context = NULL;
05286 }
05287
05288 show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05289
05290
05291 if (context && !counters.context_existence) {
05292 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05293 return CLI_FAILURE;
05294 }
05295
05296 if (exten && !counters.extension_existence) {
05297 if (context)
05298 ast_cli(a->fd, "There is no existence of %s@%s extension\n",
05299 exten, context);
05300 else
05301 ast_cli(a->fd,
05302 "There is no existence of '%s' extension in all contexts\n",
05303 exten);
05304 return CLI_FAILURE;
05305 }
05306
05307 ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
05308 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
05309 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
05310 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05311
05312
05313 return CLI_SUCCESS;
05314 }
05315
05316
05317 static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05318 {
05319 char *exten = NULL, *context = NULL;
05320
05321 struct dialplan_counters counters;
05322 const char *incstack[AST_PBX_MAX_STACK];
05323
05324 switch (cmd) {
05325 case CLI_INIT:
05326 e->command = "dialplan debug";
05327 e->usage =
05328 "Usage: dialplan debug [context]\n"
05329 " Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
05330 return NULL;
05331 case CLI_GENERATE:
05332 return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05333 }
05334
05335 memset(&counters, 0, sizeof(counters));
05336
05337 if (a->argc != 2 && a->argc != 3)
05338 return CLI_SHOWUSAGE;
05339
05340
05341
05342 if (a->argc == 3) {
05343 if (strchr(a->argv[2], '@')) {
05344 context = ast_strdupa(a->argv[2]);
05345 exten = strsep(&context, "@");
05346
05347 if (ast_strlen_zero(exten))
05348 exten = NULL;
05349 } else {
05350 context = a->argv[2];
05351 }
05352 if (ast_strlen_zero(context))
05353 context = NULL;
05354 }
05355
05356 show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05357
05358
05359 if (context && !counters.context_existence) {
05360 ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05361 return CLI_FAILURE;
05362 }
05363
05364
05365 ast_cli(a->fd,"-= %d %s. =-\n",
05366 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05367
05368
05369 return CLI_SUCCESS;
05370 }
05371
05372
05373 static void manager_dpsendack(struct mansession *s, const struct message *m)
05374 {
05375 astman_send_listack(s, m, "DialPlan list will follow", "start");
05376 }
05377
05378
05379
05380
05381
05382 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
05383 const char *actionidtext, const char *context,
05384 const char *exten, struct dialplan_counters *dpc,
05385 struct ast_include *rinclude)
05386 {
05387 struct ast_context *c;
05388 int res = 0, old_total_exten = dpc->total_exten;
05389
05390 if (ast_strlen_zero(exten))
05391 exten = NULL;
05392 if (ast_strlen_zero(context))
05393 context = NULL;
05394
05395 ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
05396
05397
05398 if (ast_rdlock_contexts()) {
05399 astman_send_error(s, m, "Failed to lock contexts");
05400 ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
05401 return -1;
05402 }
05403
05404 c = NULL;
05405 while ( (c = ast_walk_contexts(c)) ) {
05406 struct ast_exten *e;
05407 struct ast_include *i;
05408 struct ast_ignorepat *ip;
05409
05410 if (context && strcmp(ast_get_context_name(c), context) != 0)
05411 continue;
05412
05413 dpc->context_existence = 1;
05414
05415 ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
05416
05417 if (ast_rdlock_context(c)) {
05418 ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
05419 continue;
05420 }
05421
05422
05423 e = NULL;
05424 while ( (e = ast_walk_context_extensions(c, e)) ) {
05425 struct ast_exten *p;
05426
05427
05428 if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
05429
05430 ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
05431 continue;
05432 }
05433 ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
05434
05435 dpc->extension_existence = 1;
05436
05437
05438 dpc->total_context++;
05439 dpc->total_exten++;
05440
05441 p = NULL;
05442 while ( (p = ast_walk_extension_priorities(e, p)) ) {
05443 int prio = ast_get_extension_priority(p);
05444
05445 dpc->total_prio++;
05446 if (!dpc->total_items++)
05447 manager_dpsendack(s, m);
05448 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05449 astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
05450
05451
05452 if (ast_get_extension_label(p))
05453 astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
05454
05455 if (prio == PRIORITY_HINT) {
05456 astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
05457 } else {
05458 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));
05459 }
05460 astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
05461 }
05462 }
05463
05464 i = NULL;
05465 while ( (i = ast_walk_context_includes(c, i)) ) {
05466 if (exten) {
05467
05468 manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
05469 } else {
05470 if (!dpc->total_items++)
05471 manager_dpsendack(s, m);
05472 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05473 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));
05474 astman_append(s, "\r\n");
05475 ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
05476 }
05477 }
05478
05479 ip = NULL;
05480 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05481 const char *ipname = ast_get_ignorepat_name(ip);
05482 char ignorepat[AST_MAX_EXTENSION];
05483
05484 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05485 if (!exten || ast_extension_match(ignorepat, exten)) {
05486 if (!dpc->total_items++)
05487 manager_dpsendack(s, m);
05488 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05489 astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
05490 astman_append(s, "\r\n");
05491 }
05492 }
05493 if (!rinclude) {
05494 struct ast_sw *sw = NULL;
05495 while ( (sw = ast_walk_context_switches(c, sw)) ) {
05496 if (!dpc->total_items++)
05497 manager_dpsendack(s, m);
05498 astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05499 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));
05500 astman_append(s, "\r\n");
05501 ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
05502 }
05503 }
05504
05505 ast_unlock_context(c);
05506 }
05507 ast_unlock_contexts();
05508
05509 if (dpc->total_exten == old_total_exten) {
05510 ast_debug(3, "manager_show_dialplan: Found nothing new\n");
05511
05512 return -1;
05513 } else {
05514 return res;
05515 }
05516 }
05517
05518
05519 static int manager_show_dialplan(struct mansession *s, const struct message *m)
05520 {
05521 const char *exten, *context;
05522 const char *id = astman_get_header(m, "ActionID");
05523 char idtext[256];
05524 int res;
05525
05526
05527 struct dialplan_counters counters;
05528
05529 if (!ast_strlen_zero(id))
05530 snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
05531 else
05532 idtext[0] = '\0';
05533
05534 memset(&counters, 0, sizeof(counters));
05535
05536 exten = astman_get_header(m, "Extension");
05537 context = astman_get_header(m, "Context");
05538
05539 res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
05540
05541 if (context && !counters.context_existence) {
05542 char errorbuf[BUFSIZ];
05543
05544 snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
05545 astman_send_error(s, m, errorbuf);
05546 return 0;
05547 }
05548 if (exten && !counters.extension_existence) {
05549 char errorbuf[BUFSIZ];
05550
05551 if (context)
05552 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
05553 else
05554 snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
05555 astman_send_error(s, m, errorbuf);
05556 return 0;
05557 }
05558
05559 manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
05560 "EventList: Complete\r\n"
05561 "ListItems: %d\r\n"
05562 "ListExtensions: %d\r\n"
05563 "ListPriorities: %d\r\n"
05564 "ListContexts: %d\r\n"
05565 "%s"
05566 "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
05567
05568
05569 return 0;
05570 }
05571
05572 static char mandescr_show_dialplan[] =
05573 "Description: Show dialplan contexts and extensions.\n"
05574 "Be aware that showing the full dialplan may take a lot of capacity\n"
05575 "Variables: \n"
05576 " ActionID: <id> Action ID for this AMI transaction (optional)\n"
05577 " Extension: <extension> Extension (Optional)\n"
05578 " Context: <context> Context (Optional)\n"
05579 "\n";
05580
05581
05582 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05583 {
05584 int i = 0;
05585 struct ast_var_t *newvariable;
05586
05587 switch (cmd) {
05588 case CLI_INIT:
05589 e->command = "dialplan show globals";
05590 e->usage =
05591 "Usage: dialplan show globals\n"
05592 " List current global dialplan variables and their values\n";
05593 return NULL;
05594 case CLI_GENERATE:
05595 return NULL;
05596 }
05597
05598 ast_rwlock_rdlock(&globalslock);
05599 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
05600 i++;
05601 ast_cli(a->fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
05602 }
05603 ast_rwlock_unlock(&globalslock);
05604 ast_cli(a->fd, "\n -- %d variable(s)\n", i);
05605
05606 return CLI_SUCCESS;
05607 }
05608
05609 static char *handle_show_globals_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05610 {
05611
05612 char *res = handle_show_globals(e, cmd, a);
05613 if (cmd == CLI_INIT)
05614 e->command = "core show globals";
05615 return res;
05616 }
05617
05618 #ifdef AST_DEVMODE
05619 static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05620 {
05621 struct ast_devstate_aggregate agg;
05622 int i, j, exten, combined;
05623
05624 switch (cmd) {
05625 case CLI_INIT:
05626 e->command = "core show device2extenstate";
05627 e->usage =
05628 "Usage: core show device2extenstate\n"
05629 " Lists device state to extension state combinations.\n";
05630 case CLI_GENERATE:
05631 return NULL;
05632 }
05633 for (i = 0; i < AST_DEVICE_TOTAL; i++) {
05634 for (j = 0; j < AST_DEVICE_TOTAL; j++) {
05635 ast_devstate_aggregate_init(&agg);
05636 ast_devstate_aggregate_add(&agg, i);
05637 ast_devstate_aggregate_add(&agg, j);
05638 combined = ast_devstate_aggregate_result(&agg);
05639 exten = ast_devstate_to_extenstate(combined);
05640 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));
05641 }
05642 }
05643 ast_cli(a->fd, "\n");
05644 return CLI_SUCCESS;
05645 }
05646 #endif
05647
05648
05649 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05650 {
05651 struct ast_channel *chan = NULL;
05652 struct ast_str *vars = ast_str_alloca(BUFSIZ * 4);
05653
05654 switch (cmd) {
05655 case CLI_INIT:
05656 e->command = "dialplan show chanvar";
05657 e->usage =
05658 "Usage: dialplan show chanvar <channel>\n"
05659 " List current channel variables and their values\n";
05660 return NULL;
05661 case CLI_GENERATE:
05662 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05663 }
05664
05665 if (a->argc != e->args + 1)
05666 return CLI_SHOWUSAGE;
05667
05668 if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
05669 ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
05670 return CLI_FAILURE;
05671 }
05672
05673 pbx_builtin_serialize_variables(chan, &vars);
05674 if (vars->str) {
05675 ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
05676 }
05677 ast_channel_unlock(chan);
05678 return CLI_SUCCESS;
05679 }
05680
05681 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05682 {
05683 switch (cmd) {
05684 case CLI_INIT:
05685 e->command = "dialplan set global";
05686 e->usage =
05687 "Usage: dialplan set global <name> <value>\n"
05688 " Set global dialplan variable <name> to <value>\n";
05689 return NULL;
05690 case CLI_GENERATE:
05691 return NULL;
05692 }
05693
05694 if (a->argc != e->args + 2)
05695 return CLI_SHOWUSAGE;
05696
05697 pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
05698 ast_cli(a->fd, "\n -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
05699
05700 return CLI_SUCCESS;
05701 }
05702
05703 static char *handle_set_global_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05704 {
05705 char *res = handle_set_global(e, cmd, a);
05706 if (cmd == CLI_INIT)
05707 e->command = "core set global";
05708 return res;
05709 }
05710
05711 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05712 {
05713 struct ast_channel *chan;
05714 const char *chan_name, *var_name, *var_value;
05715
05716 switch (cmd) {
05717 case CLI_INIT:
05718 e->command = "dialplan set chanvar";
05719 e->usage =
05720 "Usage: dialplan set chanvar <channel> <varname> <value>\n"
05721 " Set channel variable <varname> to <value>\n";
05722 return NULL;
05723 case CLI_GENERATE:
05724 return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05725 }
05726
05727 if (a->argc != e->args + 3)
05728 return CLI_SHOWUSAGE;
05729
05730 chan_name = a->argv[e->args];
05731 var_name = a->argv[e->args + 1];
05732 var_value = a->argv[e->args + 2];
05733
05734 if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
05735 ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
05736 return CLI_FAILURE;
05737 }
05738
05739 pbx_builtin_setvar_helper(chan, var_name, var_value);
05740 ast_channel_unlock(chan);
05741 ast_cli(a->fd, "\n -- Channel variable '%s' set to '%s' for '%s'\n", var_name, var_value, chan_name);
05742
05743 return CLI_SUCCESS;
05744 }
05745
05746 static char *handle_set_chanvar_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05747 {
05748 char *res = handle_set_chanvar(e, cmd, a);
05749 if (cmd == CLI_INIT)
05750 e->command = "core set chanvar";
05751 return res;
05752 }
05753
05754 static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05755 {
05756 int oldval = 0;
05757
05758 switch (cmd) {
05759 case CLI_INIT:
05760 e->command = "dialplan set extenpatternmatchnew true";
05761 e->usage =
05762 "Usage: dialplan set extenpatternmatchnew true|false\n"
05763 " Use the NEW extension pattern matching algorithm, true or false.\n";
05764 return NULL;
05765 case CLI_GENERATE:
05766 return NULL;
05767 }
05768
05769 if (a->argc != 4)
05770 return CLI_SHOWUSAGE;
05771
05772 oldval = pbx_set_extenpatternmatchnew(1);
05773
05774 if (oldval)
05775 ast_cli(a->fd, "\n -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
05776 else
05777 ast_cli(a->fd, "\n -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
05778
05779 return CLI_SUCCESS;
05780 }
05781
05782 static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05783 {
05784 int oldval = 0;
05785
05786 switch (cmd) {
05787 case CLI_INIT:
05788 e->command = "dialplan set extenpatternmatchnew false";
05789 e->usage =
05790 "Usage: dialplan set extenpatternmatchnew true|false\n"
05791 " Use the NEW extension pattern matching algorithm, true or false.\n";
05792 return NULL;
05793 case CLI_GENERATE:
05794 return NULL;
05795 }
05796
05797 if (a->argc != 4)
05798 return CLI_SHOWUSAGE;
05799
05800 oldval = pbx_set_extenpatternmatchnew(0);
05801
05802 if (!oldval)
05803 ast_cli(a->fd, "\n -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
05804 else
05805 ast_cli(a->fd, "\n -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
05806
05807 return CLI_SUCCESS;
05808 }
05809
05810
05811
05812
05813
05814 static struct ast_cli_entry cli_show_globals_deprecated = AST_CLI_DEFINE(handle_show_globals_deprecated, "Show global dialplan variables.");
05815 static struct ast_cli_entry cli_set_chanvar_deprecated = AST_CLI_DEFINE(handle_set_chanvar_deprecated, "Set a channel variable.");
05816 static struct ast_cli_entry cli_set_global_deprecated = AST_CLI_DEFINE(handle_set_global_deprecated, "Set global dialplan variable.");
05817
05818
05819
05820
05821 static struct ast_cli_entry pbx_cli[] = {
05822 AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
05823 AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
05824 AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
05825 AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
05826 AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
05827 AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables", .deprecate_cmd = &cli_show_globals_deprecated),
05828 #ifdef AST_DEVMODE
05829 AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
05830 #endif
05831 AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
05832 AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
05833 AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
05834 AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable", .deprecate_cmd = &cli_set_global_deprecated),
05835 AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable", .deprecate_cmd = &cli_set_chanvar_deprecated),
05836 AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
05837 AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
05838 AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
05839 AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
05840 };
05841
05842 static void unreference_cached_app(struct ast_app *app)
05843 {
05844 struct ast_context *context = NULL;
05845 struct ast_exten *eroot = NULL, *e = NULL;
05846
05847 ast_rdlock_contexts();
05848 while ((context = ast_walk_contexts(context))) {
05849 while ((eroot = ast_walk_context_extensions(context, eroot))) {
05850 while ((e = ast_walk_extension_priorities(eroot, e))) {
05851 if (e->cached_app == app)
05852 e->cached_app = NULL;
05853 }
05854 }
05855 }
05856 ast_unlock_contexts();
05857
05858 return;
05859 }
05860
05861 int ast_unregister_application(const char *app)
05862 {
05863 struct ast_app *tmp;
05864
05865 AST_RWLIST_WRLOCK(&apps);
05866 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
05867 if (!strcasecmp(app, tmp->name)) {
05868 unreference_cached_app(tmp);
05869 AST_RWLIST_REMOVE_CURRENT(list);
05870 ast_verb(2, "Unregistered application '%s'\n", tmp->name);
05871 ast_free(tmp);
05872 break;
05873 }
05874 }
05875 AST_RWLIST_TRAVERSE_SAFE_END;
05876 AST_RWLIST_UNLOCK(&apps);
05877
05878 return tmp ? 0 : -1;
05879 }
05880
05881 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
05882 {
05883 struct ast_context *tmp, **local_contexts;
05884 struct fake_context search;
05885 int length = sizeof(struct ast_context) + strlen(name) + 1;
05886
05887 if (!contexts_table) {
05888 contexts_table = ast_hashtab_create(17,
05889 ast_hashtab_compare_contexts,
05890 ast_hashtab_resize_java,
05891 ast_hashtab_newsize_java,
05892 ast_hashtab_hash_contexts,
05893 0);
05894 }
05895
05896 ast_copy_string(search.name, name, sizeof(search.name));
05897 if (!extcontexts) {
05898 ast_rdlock_contexts();
05899 local_contexts = &contexts;
05900 tmp = ast_hashtab_lookup(contexts_table, &search);
05901 ast_unlock_contexts();
05902 if (tmp) {
05903 tmp->refcount++;
05904 return tmp;
05905 }
05906 } else {
05907 local_contexts = extcontexts;
05908 tmp = ast_hashtab_lookup(exttable, &search);
05909 if (tmp) {
05910 tmp->refcount++;
05911 return tmp;
05912 }
05913 }
05914
05915 if ((tmp = ast_calloc(1, length))) {
05916 ast_rwlock_init(&tmp->lock);
05917 ast_mutex_init(&tmp->macrolock);
05918 strcpy(tmp->name, name);
05919 tmp->root = NULL;
05920 tmp->root_table = NULL;
05921 tmp->registrar = ast_strdup(registrar);
05922 tmp->includes = NULL;
05923 tmp->ignorepats = NULL;
05924 tmp->refcount = 1;
05925 } else {
05926 ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
05927 return NULL;
05928 }
05929
05930 if (!extcontexts) {
05931 ast_wrlock_contexts();
05932 tmp->next = *local_contexts;
05933 *local_contexts = tmp;
05934 ast_hashtab_insert_safe(contexts_table, tmp);
05935 ast_unlock_contexts();
05936 ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05937 ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05938 } else {
05939 tmp->next = *local_contexts;
05940 if (exttable)
05941 ast_hashtab_insert_immediate(exttable, tmp);
05942
05943 *local_contexts = tmp;
05944 ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05945 ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05946 }
05947 return tmp;
05948 }
05949
05950 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
05951
05952 struct store_hint {
05953 char *context;
05954 char *exten;
05955 AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
05956 int laststate;
05957 AST_LIST_ENTRY(store_hint) list;
05958 char data[1];
05959 };
05960
05961 AST_LIST_HEAD(store_hints, store_hint);
05962
05963 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
05964 {
05965 struct ast_include *i;
05966 struct ast_ignorepat *ip;
05967 struct ast_sw *sw;
05968
05969 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);
05970
05971
05972 for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
05973 if (strcmp(ast_get_include_registrar(i), registrar) == 0)
05974 continue;
05975 ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
05976 }
05977
05978
05979 for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
05980 if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
05981 continue;
05982 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));
05983 }
05984
05985
05986 for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
05987 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
05988 continue;
05989 ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
05990 }
05991 }
05992
05993
05994
05995
05996 static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
05997 {
05998 struct ast_context *new = ast_hashtab_lookup(exttable, context);
05999 struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
06000 struct ast_hashtab_iter *exten_iter;
06001 struct ast_hashtab_iter *prio_iter;
06002 int insert_count = 0;
06003 int first = 1;
06004
06005
06006
06007
06008
06009
06010 if (context->root_table) {
06011 exten_iter = ast_hashtab_start_traversal(context->root_table);
06012 while ((exten_item=ast_hashtab_next(exten_iter))) {
06013 if (new) {
06014 new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
06015 } else {
06016 new_exten_item = NULL;
06017 }
06018 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
06019 while ((prio_item=ast_hashtab_next(prio_iter))) {
06020 int res1;
06021 char *dupdstr;
06022
06023 if (new_exten_item) {
06024 new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
06025 } else {
06026 new_prio_item = NULL;
06027 }
06028 if (strcmp(prio_item->registrar,registrar) == 0) {
06029 continue;
06030 }
06031
06032 if (!new) {
06033 new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar);
06034 }
06035
06036
06037 if (first) {
06038 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06039 first = 0;
06040 }
06041
06042 if (!new) {
06043 ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
06044 return;
06045 }
06046
06047
06048
06049 dupdstr = ast_strdup(prio_item->data);
06050
06051 res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
06052 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
06053 if (!res1 && new_exten_item && new_prio_item){
06054 ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
06055 context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
06056 } else {
06057
06058
06059 insert_count++;
06060 }
06061 }
06062 ast_hashtab_end_traversal(prio_iter);
06063 }
06064 ast_hashtab_end_traversal(exten_iter);
06065 }
06066
06067 if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
06068 (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
06069
06070
06071 new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
06072
06073
06074 context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06075 }
06076 }
06077
06078
06079
06080 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
06081 {
06082 double ft;
06083 struct ast_context *tmp, *oldcontextslist;
06084 struct ast_hashtab *oldtable;
06085 struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
06086 struct store_hint *this;
06087 struct ast_hint *hint;
06088 struct ast_exten *exten;
06089 int length;
06090 struct ast_state_cb *thiscb;
06091 struct ast_hashtab_iter *iter;
06092
06093
06094
06095
06096
06097
06098
06099
06100
06101
06102 struct timeval begintime, writelocktime, endlocktime, enddeltime;
06103 int wrlock_ver;
06104
06105 begintime = ast_tvnow();
06106 ast_rdlock_contexts();
06107 iter = ast_hashtab_start_traversal(contexts_table);
06108 while ((tmp = ast_hashtab_next(iter))) {
06109 context_merge(extcontexts, exttable, tmp, registrar);
06110 }
06111 ast_hashtab_end_traversal(iter);
06112 wrlock_ver = ast_wrlock_contexts_version();
06113
06114 ast_unlock_contexts();
06115
06116
06117 ast_wrlock_contexts();
06118 if (ast_wrlock_contexts_version() > wrlock_ver+1) {
06119 ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
06120 }
06121
06122 AST_RWLIST_WRLOCK(&hints);
06123 writelocktime = ast_tvnow();
06124
06125
06126 AST_RWLIST_TRAVERSE(&hints, hint, list) {
06127 if (!AST_LIST_EMPTY(&hint->callbacks)) {
06128 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
06129 if (!(this = ast_calloc(1, length)))
06130 continue;
06131
06132 AST_LIST_APPEND_LIST(&this->callbacks, &hint->callbacks, entry);
06133 this->laststate = hint->laststate;
06134 this->context = this->data;
06135 strcpy(this->data, hint->exten->parent->name);
06136 this->exten = this->data + strlen(this->context) + 1;
06137 strcpy(this->exten, hint->exten->exten);
06138 AST_LIST_INSERT_HEAD(&store, this, list);
06139 }
06140 }
06141
06142
06143 oldtable = contexts_table;
06144 oldcontextslist = contexts;
06145
06146
06147 contexts_table = exttable;
06148 contexts = *extcontexts;
06149
06150
06151
06152
06153 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
06154 struct pbx_find_info q = { .stacklen = 0 };
06155 exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
06156
06157
06158
06159
06160 if (exten && exten->exten[0] == '_') {
06161 ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
06162 0, exten->app, ast_strdup(exten->data), ast_free_ptr, exten->registrar);
06163
06164 exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
06165 }
06166
06167
06168 AST_RWLIST_TRAVERSE(&hints, hint, list) {
06169 if (hint->exten == exten)
06170 break;
06171 }
06172 if (!exten || !hint) {
06173
06174 while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
06175 thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data);
06176 ast_free(thiscb);
06177 }
06178 } else {
06179 AST_LIST_APPEND_LIST(&hint->callbacks, &this->callbacks, entry);
06180 hint->laststate = this->laststate;
06181 }
06182 ast_free(this);
06183 }
06184
06185 AST_RWLIST_UNLOCK(&hints);
06186 ast_unlock_contexts();
06187 endlocktime = ast_tvnow();
06188
06189
06190
06191
06192 ast_hashtab_destroy(oldtable, NULL);
06193
06194 for (tmp = oldcontextslist; tmp; ) {
06195 struct ast_context *next;
06196 next = tmp->next;
06197 __ast_internal_context_destroy(tmp);
06198 tmp = next;
06199 }
06200 enddeltime = ast_tvnow();
06201
06202 ft = ast_tvdiff_us(writelocktime, begintime);
06203 ft /= 1000000.0;
06204 ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
06205
06206 ft = ast_tvdiff_us(endlocktime, writelocktime);
06207 ft /= 1000000.0;
06208 ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
06209
06210 ft = ast_tvdiff_us(enddeltime, endlocktime);
06211 ft /= 1000000.0;
06212 ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
06213
06214 ft = ast_tvdiff_us(enddeltime, begintime);
06215 ft /= 1000000.0;
06216 ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
06217 return;
06218 }
06219
06220
06221
06222
06223
06224
06225 int ast_context_add_include(const char *context, const char *include, const char *registrar)
06226 {
06227 int ret = -1;
06228 struct ast_context *c = find_context_locked(context);
06229
06230 if (c) {
06231 ret = ast_context_add_include2(c, include, registrar);
06232 ast_unlock_contexts();
06233 }
06234 return ret;
06235 }
06236
06237
06238
06239
06240
06241 static int lookup_name(const char *s, char *const names[], int max)
06242 {
06243 int i;
06244
06245 if (names) {
06246 for (i = 0; names[i]; i++) {
06247 if (!strcasecmp(s, names[i]))
06248 return i+1;
06249 }
06250 } else if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
06251 return i;
06252 }
06253 return 0;
06254 }
06255
06256
06257
06258
06259 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
06260 {
06261 int s, e;
06262 unsigned int mask = 0;
06263
06264
06265 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
06266 s = 0;
06267 e = max - 1;
06268 } else {
06269
06270 char *c = strchr(src, '-');
06271 if (c)
06272 *c++ = '\0';
06273
06274 s = lookup_name(src, names, max);
06275 if (!s) {
06276 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
06277 return 0;
06278 }
06279 s--;
06280 if (c) {
06281 e = lookup_name(c, names, max);
06282 if (!e) {
06283 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
06284 return 0;
06285 }
06286 e--;
06287 } else
06288 e = s;
06289 }
06290
06291 mask = 1 << e;
06292 while (s != e) {
06293 if (s >= max) {
06294 s = 0;
06295 mask |= (1 << s);
06296 } else {
06297 mask |= (1 << s);
06298 s++;
06299 }
06300 }
06301 return mask;
06302 }
06303
06304
06305 static void get_timerange(struct ast_timing *i, char *times)
06306 {
06307 char *e;
06308 int x;
06309 int s1, s2;
06310 int e1, e2;
06311
06312
06313
06314 memset(i->minmask, 0, sizeof(i->minmask));
06315
06316
06317
06318 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
06319 for (x = 0; x < 24; x++)
06320 i->minmask[x] = 0x3fffffff;
06321 return;
06322 }
06323
06324 e = strchr(times, '-');
06325 if (!e) {
06326 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
06327 return;
06328 }
06329 *e++ = '\0';
06330
06331 while (*e && !isdigit(*e))
06332 e++;
06333 if (!*e) {
06334 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
06335 return;
06336 }
06337 if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
06338 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
06339 return;
06340 }
06341 if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
06342 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
06343 return;
06344 }
06345
06346 #if 1
06347 s1 = s1 * 30 + s2/2;
06348 if ((s1 < 0) || (s1 >= 24*30)) {
06349 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
06350 return;
06351 }
06352 e1 = e1 * 30 + e2/2;
06353 if ((e1 < 0) || (e1 >= 24*30)) {
06354 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
06355 return;
06356 }
06357
06358 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
06359 i->minmask[x/30] |= (1 << (x % 30));
06360 }
06361
06362 i->minmask[x/30] |= (1 << (x % 30));
06363 #else
06364 for (cth = 0; cth < 24; cth++) {
06365
06366 i->minmask[cth] = 0;
06367 for (ctm = 0; ctm < 30; ctm++) {
06368 if (
06369
06370 (((cth == s1) && (ctm >= s2)) &&
06371 ((cth < e1)))
06372
06373 || (((cth == s1) && (ctm >= s2)) &&
06374 ((cth == e1) && (ctm <= e2)))
06375
06376 || ((cth > s1) &&
06377 (cth < e1))
06378
06379 || ((cth > s1) &&
06380 ((cth == e1) && (ctm <= e2)))
06381 )
06382 i->minmask[cth] |= (1 << (ctm / 2));
06383 }
06384 }
06385 #endif
06386
06387 return;
06388 }
06389
06390 static char *days[] =
06391 {
06392 "sun",
06393 "mon",
06394 "tue",
06395 "wed",
06396 "thu",
06397 "fri",
06398 "sat",
06399 NULL,
06400 };
06401
06402 static char *months[] =
06403 {
06404 "jan",
06405 "feb",
06406 "mar",
06407 "apr",
06408 "may",
06409 "jun",
06410 "jul",
06411 "aug",
06412 "sep",
06413 "oct",
06414 "nov",
06415 "dec",
06416 NULL,
06417 };
06418
06419 int ast_build_timing(struct ast_timing *i, const char *info_in)
06420 {
06421 char info_save[256];
06422 char *info;
06423
06424
06425 if (ast_strlen_zero(info_in))
06426 return 0;
06427
06428 ast_copy_string(info_save, info_in, sizeof(info_save));
06429 info = info_save;
06430
06431 i->monthmask = 0xfff;
06432 i->daymask = 0x7fffffffU;
06433 i->dowmask = 0x7f;
06434
06435 get_timerange(i, strsep(&info, "|,"));
06436 if (info)
06437 i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
06438 if (info)
06439 i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
06440 if (info)
06441 i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
06442 return 1;
06443 }
06444
06445 int ast_check_timing(const struct ast_timing *i)
06446 {
06447 struct ast_tm tm;
06448 struct timeval now = ast_tvnow();
06449
06450 ast_localtime(&now, &tm, NULL);
06451
06452
06453 if (!(i->monthmask & (1 << tm.tm_mon)))
06454 return 0;
06455
06456
06457
06458 if (!(i->daymask & (1 << (tm.tm_mday-1))))
06459 return 0;
06460
06461
06462 if (!(i->dowmask & (1 << tm.tm_wday)))
06463 return 0;
06464
06465
06466 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
06467 ast_log(LOG_WARNING, "Insane time...\n");
06468 return 0;
06469 }
06470
06471
06472
06473 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
06474 return 0;
06475
06476
06477 return 1;
06478 }
06479
06480
06481
06482
06483
06484
06485
06486
06487 int ast_context_add_include2(struct ast_context *con, const char *value,
06488 const char *registrar)
06489 {
06490 struct ast_include *new_include;
06491 char *c;
06492 struct ast_include *i, *il = NULL;
06493 int length;
06494 char *p;
06495
06496 length = sizeof(struct ast_include);
06497 length += 2 * (strlen(value) + 1);
06498
06499
06500 if (!(new_include = ast_calloc(1, length)))
06501 return -1;
06502
06503
06504
06505 p = new_include->stuff;
06506 new_include->name = p;
06507 strcpy(p, value);
06508 p += strlen(value) + 1;
06509 new_include->rname = p;
06510 strcpy(p, value);
06511
06512 if ( (c = strchr(p, ',')) ) {
06513 *c++ = '\0';
06514 new_include->hastime = ast_build_timing(&(new_include->timing), c);
06515 }
06516 new_include->next = NULL;
06517 new_include->registrar = registrar;
06518
06519 ast_wrlock_context(con);
06520
06521
06522 for (i = con->includes; i; i = i->next) {
06523 if (!strcasecmp(i->name, new_include->name)) {
06524 ast_free(new_include);
06525 ast_unlock_context(con);
06526 errno = EEXIST;
06527 return -1;
06528 }
06529 il = i;
06530 }
06531
06532
06533 if (il)
06534 il->next = new_include;
06535 else
06536 con->includes = new_include;
06537 ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
06538
06539 ast_unlock_context(con);
06540
06541 return 0;
06542 }
06543
06544
06545
06546
06547
06548
06549 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
06550 {
06551 int ret = -1;
06552 struct ast_context *c = find_context_locked(context);
06553
06554 if (c) {
06555 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
06556 ast_unlock_contexts();
06557 }
06558 return ret;
06559 }
06560
06561
06562
06563
06564
06565
06566
06567
06568 int ast_context_add_switch2(struct ast_context *con, const char *value,
06569 const char *data, int eval, const char *registrar)
06570 {
06571 struct ast_sw *new_sw;
06572 struct ast_sw *i;
06573 int length;
06574 char *p;
06575
06576 length = sizeof(struct ast_sw);
06577 length += strlen(value) + 1;
06578 if (data)
06579 length += strlen(data);
06580 length++;
06581
06582
06583 if (!(new_sw = ast_calloc(1, length)))
06584 return -1;
06585
06586 p = new_sw->stuff;
06587 new_sw->name = p;
06588 strcpy(new_sw->name, value);
06589 p += strlen(value) + 1;
06590 new_sw->data = p;
06591 if (data) {
06592 strcpy(new_sw->data, data);
06593 p += strlen(data) + 1;
06594 } else {
06595 strcpy(new_sw->data, "");
06596 p++;
06597 }
06598 new_sw->eval = eval;
06599 new_sw->registrar = registrar;
06600
06601
06602 ast_wrlock_context(con);
06603
06604
06605 AST_LIST_TRAVERSE(&con->alts, i, list) {
06606 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
06607 ast_free(new_sw);
06608 ast_unlock_context(con);
06609 errno = EEXIST;
06610 return -1;
06611 }
06612 }
06613
06614
06615 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
06616
06617 ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
06618
06619 ast_unlock_context(con);
06620
06621 return 0;
06622 }
06623
06624
06625
06626
06627
06628 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
06629 {
06630 int ret = -1;
06631 struct ast_context *c = find_context_locked(context);
06632
06633 if (c) {
06634 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
06635 ast_unlock_contexts();
06636 }
06637 return ret;
06638 }
06639
06640 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
06641 {
06642 struct ast_ignorepat *ip, *ipl = NULL;
06643
06644 ast_wrlock_context(con);
06645
06646 for (ip = con->ignorepats; ip; ip = ip->next) {
06647 if (!strcmp(ip->pattern, ignorepat) &&
06648 (!registrar || (registrar == ip->registrar))) {
06649 if (ipl) {
06650 ipl->next = ip->next;
06651 ast_free(ip);
06652 } else {
06653 con->ignorepats = ip->next;
06654 ast_free(ip);
06655 }
06656 ast_unlock_context(con);
06657 return 0;
06658 }
06659 ipl = ip;
06660 }
06661
06662 ast_unlock_context(con);
06663 errno = EINVAL;
06664 return -1;
06665 }
06666
06667
06668
06669
06670
06671 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
06672 {
06673 int ret = -1;
06674 struct ast_context *c = find_context_locked(context);
06675
06676 if (c) {
06677 ret = ast_context_add_ignorepat2(c, value, registrar);
06678 ast_unlock_contexts();
06679 }
06680 return ret;
06681 }
06682
06683 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
06684 {
06685 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
06686 int length;
06687 char *pattern;
06688 length = sizeof(struct ast_ignorepat);
06689 length += strlen(value) + 1;
06690 if (!(ignorepat = ast_calloc(1, length)))
06691 return -1;
06692
06693
06694
06695
06696
06697
06698 pattern = (char *) ignorepat->pattern;
06699 strcpy(pattern, value);
06700 ignorepat->next = NULL;
06701 ignorepat->registrar = registrar;
06702 ast_wrlock_context(con);
06703 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
06704 ignorepatl = ignorepatc;
06705 if (!strcasecmp(ignorepatc->pattern, value)) {
06706
06707 ast_unlock_context(con);
06708 errno = EEXIST;
06709 return -1;
06710 }
06711 }
06712 if (ignorepatl)
06713 ignorepatl->next = ignorepat;
06714 else
06715 con->ignorepats = ignorepat;
06716 ast_unlock_context(con);
06717 return 0;
06718
06719 }
06720
06721 int ast_ignore_pattern(const char *context, const char *pattern)
06722 {
06723 struct ast_context *con = ast_context_find(context);
06724 if (con) {
06725 struct ast_ignorepat *pat;
06726 for (pat = con->ignorepats; pat; pat = pat->next) {
06727 if (ast_extension_match(pat->pattern, pattern))
06728 return 1;
06729 }
06730 }
06731
06732 return 0;
06733 }
06734
06735
06736
06737
06738
06739
06740 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
06741 int priority, const char *label, const char *callerid,
06742 const char *application, void *data, void (*datad)(void *), const char *registrar)
06743 {
06744 int ret = -1;
06745 struct ast_context *c = find_context(context);
06746
06747 if (c) {
06748 ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
06749 application, data, datad, registrar, 0, 0);
06750 }
06751
06752 return ret;
06753 }
06754
06755
06756
06757
06758
06759 int ast_add_extension(const char *context, int replace, const char *extension,
06760 int priority, const char *label, const char *callerid,
06761 const char *application, void *data, void (*datad)(void *), const char *registrar)
06762 {
06763 int ret = -1;
06764 struct ast_context *c = find_context_locked(context);
06765
06766 if (c) {
06767 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
06768 application, data, datad, registrar);
06769 ast_unlock_contexts();
06770 }
06771
06772 return ret;
06773 }
06774
06775 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
06776 {
06777 if (!chan)
06778 return -1;
06779
06780 ast_channel_lock(chan);
06781
06782 if (!ast_strlen_zero(context))
06783 ast_copy_string(chan->context, context, sizeof(chan->context));
06784 if (!ast_strlen_zero(exten))
06785 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06786 if (priority > -1) {
06787 chan->priority = priority;
06788
06789 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
06790 chan->priority--;
06791 }
06792
06793 ast_channel_unlock(chan);
06794
06795 return 0;
06796 }
06797
06798 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
06799 {
06800 int res = 0;
06801
06802 ast_channel_lock(chan);
06803
06804 if (chan->pbx) {
06805 ast_explicit_goto(chan, context, exten, priority + 1);
06806 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
06807 } else {
06808
06809
06810
06811 struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
06812 if (!tmpchan) {
06813 res = -1;
06814 } else {
06815 if (chan->cdr) {
06816 ast_cdr_discard(tmpchan->cdr);
06817 tmpchan->cdr = ast_cdr_dup(chan->cdr);
06818 }
06819
06820 tmpchan->readformat = chan->readformat;
06821 tmpchan->writeformat = chan->writeformat;
06822
06823 ast_explicit_goto(tmpchan,
06824 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
06825
06826
06827 if (ast_channel_masquerade(tmpchan, chan)) {
06828
06829
06830 ast_hangup(tmpchan);
06831 tmpchan = NULL;
06832 res = -1;
06833 } else {
06834
06835 ast_channel_lock(tmpchan);
06836 ast_do_masquerade(tmpchan);
06837 ast_channel_unlock(tmpchan);
06838
06839 if (ast_pbx_start(tmpchan)) {
06840 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
06841 ast_hangup(tmpchan);
06842 res = -1;
06843 }
06844 }
06845 }
06846 }
06847 ast_channel_unlock(chan);
06848 return res;
06849 }
06850
06851 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
06852 {
06853 struct ast_channel *chan;
06854 int res = -1;
06855
06856 chan = ast_get_channel_by_name_locked(channame);
06857 if (chan) {
06858 res = ast_async_goto(chan, context, exten, priority);
06859 ast_channel_unlock(chan);
06860 }
06861 return res;
06862 }
06863
06864
06865 static int ext_strncpy(char *dst, const char *src, int len)
06866 {
06867 int count = 0;
06868
06869 while (*src && (count < len - 1)) {
06870 switch (*src) {
06871 case ' ':
06872
06873
06874
06875 break;
06876 default:
06877 *dst = *src;
06878 dst++;
06879 }
06880 src++;
06881 count++;
06882 }
06883 *dst = '\0';
06884
06885 return count;
06886 }
06887
06888
06889
06890
06891
06892
06893 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
06894 struct ast_exten *el, struct ast_exten *e, int replace)
06895 {
06896 return add_pri_lockopt(con, tmp, el, e, replace, 1);
06897 }
06898
06899
06900
06901
06902
06903
06904 static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
06905 struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
06906 {
06907 struct ast_exten *ep;
06908 struct ast_exten *eh=e;
06909
06910 for (ep = NULL; e ; ep = e, e = e->peer) {
06911 if (e->priority >= tmp->priority)
06912 break;
06913 }
06914 if (!e) {
06915 ast_hashtab_insert_safe(eh->peer_table, tmp);
06916
06917 if (tmp->label) {
06918 ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06919 }
06920 ep->peer = tmp;
06921 return 0;
06922 }
06923 if (e->priority == tmp->priority) {
06924
06925
06926 if (!replace) {
06927 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
06928 if (tmp->datad) {
06929 tmp->datad(tmp->data);
06930
06931 tmp->data = NULL;
06932 }
06933
06934 ast_free(tmp);
06935 return -1;
06936 }
06937
06938
06939
06940 tmp->next = e->next;
06941 tmp->peer = e->peer;
06942 if (ep) {
06943 ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
06944
06945 if (e->label) {
06946 ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
06947 }
06948
06949 ast_hashtab_insert_safe(eh->peer_table,tmp);
06950 if (tmp->label) {
06951 ast_hashtab_insert_safe(eh->peer_label_table,tmp);
06952 }
06953
06954 ep->peer = tmp;
06955 } else if (el) {
06956 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06957 tmp->peer_table = e->peer_table;
06958 tmp->peer_label_table = e->peer_label_table;
06959 ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
06960 ast_hashtab_insert_safe(tmp->peer_table,tmp);
06961 if (e->label) {
06962 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06963 }
06964 if (tmp->label) {
06965 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06966 }
06967
06968 ast_hashtab_remove_object_via_lookup(con->root_table, e);
06969 ast_hashtab_insert_safe(con->root_table, tmp);
06970 el->next = tmp;
06971
06972
06973 if (x) {
06974 if (x->exten) {
06975 x->exten = tmp;
06976 } else {
06977 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06978 }
06979 }
06980 } else {
06981 struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06982 ast_hashtab_remove_object_via_lookup(con->root_table, e);
06983 ast_hashtab_insert_safe(con->root_table, tmp);
06984 tmp->peer_table = e->peer_table;
06985 tmp->peer_label_table = e->peer_label_table;
06986 ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
06987 ast_hashtab_insert_safe(tmp->peer_table, tmp);
06988 if (e->label) {
06989 ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06990 }
06991 if (tmp->label) {
06992 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06993 }
06994
06995 ast_hashtab_remove_object_via_lookup(con->root_table, e);
06996 ast_hashtab_insert_safe(con->root_table, tmp);
06997 con->root = tmp;
06998
06999
07000 if (x) {
07001 if (x->exten) {
07002 x->exten = tmp;
07003 } else {
07004 ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
07005 }
07006 }
07007 }
07008 if (tmp->priority == PRIORITY_HINT)
07009 ast_change_hint(e,tmp);
07010
07011 if (e->datad)
07012 e->datad(e->data);
07013 ast_free(e);
07014 } else {
07015 tmp->peer = e;
07016 tmp->next = e->next;
07017 if (ep) {
07018 if (tmp->label) {
07019 ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07020 }
07021 ast_hashtab_insert_safe(eh->peer_table, tmp);
07022 ep->peer = tmp;
07023 } else {
07024 tmp->peer_table = e->peer_table;
07025 tmp->peer_label_table = e->peer_label_table;
07026 e->peer_table = 0;
07027 e->peer_label_table = 0;
07028 ast_hashtab_insert_safe(tmp->peer_table, tmp);
07029 if (tmp->label) {
07030 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07031 }
07032 ast_hashtab_remove_object_via_lookup(con->root_table, e);
07033 ast_hashtab_insert_safe(con->root_table, tmp);
07034 if (el)
07035 el->next = tmp;
07036 else
07037 con->root = tmp;
07038 e->next = NULL;
07039 }
07040
07041 if (tmp->priority == PRIORITY_HINT) {
07042 if (lockhints) {
07043 ast_add_hint(tmp);
07044 } else {
07045 ast_add_hint_nolock(tmp);
07046 }
07047 }
07048 }
07049 return 0;
07050 }
07051
07052
07053
07054
07055
07056
07057
07058
07059
07060
07061
07062
07063
07064
07065
07066
07067
07068
07069
07070
07071
07072
07073
07074
07075
07076
07077 int ast_add_extension2(struct ast_context *con,
07078 int replace, const char *extension, int priority, const char *label, const char *callerid,
07079 const char *application, void *data, void (*datad)(void *),
07080 const char *registrar)
07081 {
07082 return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07083 }
07084
07085
07086
07087
07088
07089
07090 static int ast_add_extension2_lockopt(struct ast_context *con,
07091 int replace, const char *extension, int priority, const char *label, const char *callerid,
07092 const char *application, void *data, void (*datad)(void *),
07093 const char *registrar, int lockconts, int lockhints)
07094 {
07095
07096
07097
07098
07099
07100
07101 struct ast_exten *tmp, *tmp2, *e, *el = NULL;
07102 int res;
07103 int length;
07104 char *p;
07105 char expand_buf[VAR_BUF_SIZE];
07106 struct ast_exten dummy_exten = {0};
07107 char dummy_name[1024];
07108
07109 if (ast_strlen_zero(extension)) {
07110 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",
07111 con->name);
07112 return -1;
07113 }
07114
07115
07116 if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
07117 struct ast_channel c = {0, };
07118
07119 ast_copy_string(c.exten, extension, sizeof(c.exten));
07120 ast_copy_string(c.context, con->name, sizeof(c.context));
07121 pbx_substitute_variables_helper(&c, application, expand_buf, sizeof(expand_buf));
07122 application = expand_buf;
07123 }
07124
07125 length = sizeof(struct ast_exten);
07126 length += strlen(extension) + 1;
07127 length += strlen(application) + 1;
07128 if (label)
07129 length += strlen(label) + 1;
07130 if (callerid)
07131 length += strlen(callerid) + 1;
07132 else
07133 length ++;
07134
07135
07136 if (!(tmp = ast_calloc(1, length)))
07137 return -1;
07138
07139 if (ast_strlen_zero(label))
07140 label = 0;
07141
07142
07143 p = tmp->stuff;
07144 if (label) {
07145 tmp->label = p;
07146 strcpy(p, label);
07147 p += strlen(label) + 1;
07148 }
07149 tmp->exten = p;
07150 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
07151 tmp->priority = priority;
07152 tmp->cidmatch = p;
07153
07154
07155 if (callerid) {
07156 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
07157 tmp->matchcid = 1;
07158 } else {
07159 *p++ = '\0';
07160 tmp->matchcid = 0;
07161 }
07162 tmp->app = p;
07163 strcpy(p, application);
07164 tmp->parent = con;
07165 tmp->data = data;
07166 tmp->datad = datad;
07167 tmp->registrar = registrar;
07168
07169 if (lockconts) {
07170 ast_wrlock_context(con);
07171 }
07172
07173 if (con->pattern_tree) {
07174
07175 ast_copy_string(dummy_name, extension, sizeof(dummy_name));
07176 dummy_exten.exten = dummy_name;
07177 dummy_exten.matchcid = 0;
07178 dummy_exten.cidmatch = 0;
07179 tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
07180 if (!tmp2) {
07181
07182 add_exten_to_pattern_tree(con, tmp, 0);
07183 ast_hashtab_insert_safe(con->root_table, tmp);
07184 }
07185 }
07186 res = 0;
07187 for (e = con->root; e; el = e, e = e->next) {
07188 res = ext_cmp(e->exten, tmp->exten);
07189 if (res == 0) {
07190 if (!e->matchcid && !tmp->matchcid)
07191 res = 0;
07192 else if (tmp->matchcid && !e->matchcid)
07193 res = 1;
07194 else if (e->matchcid && !tmp->matchcid)
07195 res = -1;
07196 else
07197 res = ext_cmp(e->cidmatch, tmp->cidmatch);
07198 }
07199 if (res >= 0)
07200 break;
07201 }
07202 if (e && res == 0) {
07203 res = add_pri(con, tmp, el, e, replace);
07204 if (lockconts) {
07205 ast_unlock_context(con);
07206 }
07207 if (res < 0) {
07208 errno = EEXIST;
07209 return 0;
07210 }
07211 } else {
07212
07213
07214
07215
07216 tmp->next = e;
07217 if (el) {
07218 el->next = tmp;
07219 tmp->peer_table = ast_hashtab_create(13,
07220 hashtab_compare_exten_numbers,
07221 ast_hashtab_resize_java,
07222 ast_hashtab_newsize_java,
07223 hashtab_hash_priority,
07224 0);
07225 tmp->peer_label_table = ast_hashtab_create(7,
07226 hashtab_compare_exten_labels,
07227 ast_hashtab_resize_java,
07228 ast_hashtab_newsize_java,
07229 hashtab_hash_labels,
07230 0);
07231 if (label) {
07232 ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07233 }
07234 ast_hashtab_insert_safe(tmp->peer_table, tmp);
07235 } else {
07236 if (!con->root_table)
07237 con->root_table = ast_hashtab_create(27,
07238 hashtab_compare_extens,
07239 ast_hashtab_resize_java,
07240 ast_hashtab_newsize_java,
07241 hashtab_hash_extens,
07242 0);
07243 con->root = tmp;
07244 con->root->peer_table = ast_hashtab_create(13,
07245 hashtab_compare_exten_numbers,
07246 ast_hashtab_resize_java,
07247 ast_hashtab_newsize_java,
07248 hashtab_hash_priority,
07249 0);
07250 con->root->peer_label_table = ast_hashtab_create(7,
07251 hashtab_compare_exten_labels,
07252 ast_hashtab_resize_java,
07253 ast_hashtab_newsize_java,
07254 hashtab_hash_labels,
07255 0);
07256 if (label) {
07257 ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
07258 }
07259 ast_hashtab_insert_safe(con->root->peer_table, tmp);
07260
07261 }
07262 ast_hashtab_insert_safe(con->root_table, tmp);
07263 if (lockconts) {
07264 ast_unlock_context(con);
07265 }
07266 if (tmp->priority == PRIORITY_HINT) {
07267 if (lockhints) {
07268 ast_add_hint(tmp);
07269 } else {
07270 ast_add_hint_nolock(tmp);
07271 }
07272 }
07273 }
07274 if (option_debug) {
07275 if (tmp->matchcid) {
07276 ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07277 tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07278 } else {
07279 ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
07280 tmp->exten, tmp->priority, con->name, con);
07281 }
07282 }
07283
07284 if (tmp->matchcid) {
07285 ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07286 tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07287 } else {
07288 ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
07289 tmp->exten, tmp->priority, con->name, con);
07290 }
07291
07292 return 0;
07293 }
07294
07295 struct async_stat {
07296 pthread_t p;
07297 struct ast_channel *chan;
07298 char context[AST_MAX_CONTEXT];
07299 char exten[AST_MAX_EXTENSION];
07300 int priority;
07301 int timeout;
07302 char app[AST_MAX_EXTENSION];
07303 char appdata[1024];
07304 };
07305
07306 static void *async_wait(void *data)
07307 {
07308 struct async_stat *as = data;
07309 struct ast_channel *chan = as->chan;
07310 int timeout = as->timeout;
07311 int res;
07312 struct ast_frame *f;
07313 struct ast_app *app;
07314
07315 while (timeout && (chan->_state != AST_STATE_UP)) {
07316 res = ast_waitfor(chan, timeout);
07317 if (res < 1)
07318 break;
07319 if (timeout > -1)
07320 timeout = res;
07321 f = ast_read(chan);
07322 if (!f)
07323 break;
07324 if (f->frametype == AST_FRAME_CONTROL) {
07325 if ((f->subclass == AST_CONTROL_BUSY) ||
07326 (f->subclass == AST_CONTROL_CONGESTION) ) {
07327 ast_frfree(f);
07328 break;
07329 }
07330 }
07331 ast_frfree(f);
07332 }
07333 if (chan->_state == AST_STATE_UP) {
07334 if (!ast_strlen_zero(as->app)) {
07335 app = pbx_findapp(as->app);
07336 if (app) {
07337 ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
07338 pbx_exec(chan, app, as->appdata);
07339 } else
07340 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
07341 } else {
07342 if (!ast_strlen_zero(as->context))
07343 ast_copy_string(chan->context, as->context, sizeof(chan->context));
07344 if (!ast_strlen_zero(as->exten))
07345 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
07346 if (as->priority > 0)
07347 chan->priority = as->priority;
07348
07349 if (ast_pbx_run(chan)) {
07350 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
07351 } else {
07352
07353 chan = NULL;
07354 }
07355 }
07356 }
07357 ast_free(as);
07358 if (chan)
07359 ast_hangup(chan);
07360 return NULL;
07361 }
07362
07363
07364
07365
07366
07367 static int ast_pbx_outgoing_cdr_failed(void)
07368 {
07369
07370 struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
07371
07372 if (!chan)
07373 return -1;
07374
07375 if (!chan->cdr) {
07376
07377 ast_channel_free(chan);
07378 return -1;
07379 }
07380
07381
07382 ast_cdr_init(chan->cdr, chan);
07383 ast_cdr_start(chan->cdr);
07384 ast_cdr_end(chan->cdr);
07385 ast_cdr_failed(chan->cdr);
07386 ast_cdr_detach(chan->cdr);
07387 chan->cdr = NULL;
07388 ast_channel_free(chan);
07389
07390 return 0;
07391 }
07392
07393 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)
07394 {
07395 struct ast_channel *chan;
07396 struct async_stat *as;
07397 int res = -1, cdr_res = -1;
07398 struct outgoing_helper oh;
07399
07400 if (synchronous) {
07401 oh.context = context;
07402 oh.exten = exten;
07403 oh.priority = priority;
07404 oh.cid_num = cid_num;
07405 oh.cid_name = cid_name;
07406 oh.account = account;
07407 oh.vars = vars;
07408 oh.parent_channel = NULL;
07409
07410 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07411 if (channel) {
07412 *channel = chan;
07413 if (chan)
07414 ast_channel_lock(chan);
07415 }
07416 if (chan) {
07417 if (chan->_state == AST_STATE_UP) {
07418 res = 0;
07419 ast_verb(4, "Channel %s was answered.\n", chan->name);
07420
07421 if (synchronous > 1) {
07422 if (channel)
07423 ast_channel_unlock(chan);
07424 if (ast_pbx_run(chan)) {
07425 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07426 if (channel)
07427 *channel = NULL;
07428 ast_hangup(chan);
07429 chan = NULL;
07430 res = -1;
07431 }
07432 } else {
07433 if (ast_pbx_start(chan)) {
07434 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
07435 if (channel) {
07436 *channel = NULL;
07437 ast_channel_unlock(chan);
07438 }
07439 ast_hangup(chan);
07440 res = -1;
07441 }
07442 chan = NULL;
07443 }
07444 } else {
07445 ast_verb(4, "Channel %s was never answered.\n", chan->name);
07446
07447 if (chan->cdr) {
07448
07449
07450 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07451 ast_cdr_failed(chan->cdr);
07452 }
07453
07454 if (channel) {
07455 *channel = NULL;
07456 ast_channel_unlock(chan);
07457 }
07458 ast_hangup(chan);
07459 chan = NULL;
07460 }
07461 }
07462
07463 if (res < 0) {
07464 if (*reason == 0) {
07465
07466 cdr_res = ast_pbx_outgoing_cdr_failed();
07467 if (cdr_res != 0) {
07468 res = cdr_res;
07469 goto outgoing_exten_cleanup;
07470 }
07471 }
07472
07473
07474
07475 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
07476 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
07477 if (chan) {
07478 char failed_reason[4] = "";
07479 if (!ast_strlen_zero(context))
07480 ast_copy_string(chan->context, context, sizeof(chan->context));
07481 set_ext_pri(chan, "failed", 1);
07482 ast_set_variables(chan, vars);
07483 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
07484 pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
07485 if (account)
07486 ast_cdr_setaccount(chan, account);
07487 if (ast_pbx_run(chan)) {
07488 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07489 ast_hangup(chan);
07490 }
07491 chan = NULL;
07492 }
07493 }
07494 }
07495 } else {
07496 if (!(as = ast_calloc(1, sizeof(*as)))) {
07497 res = -1;
07498 goto outgoing_exten_cleanup;
07499 }
07500 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
07501 if (channel) {
07502 *channel = chan;
07503 if (chan)
07504 ast_channel_lock(chan);
07505 }
07506 if (!chan) {
07507 ast_free(as);
07508 res = -1;
07509 goto outgoing_exten_cleanup;
07510 }
07511 as->chan = chan;
07512 ast_copy_string(as->context, context, sizeof(as->context));
07513 set_ext_pri(as->chan, exten, priority);
07514 as->timeout = timeout;
07515 ast_set_variables(chan, vars);
07516 if (account)
07517 ast_cdr_setaccount(chan, account);
07518 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07519 ast_log(LOG_WARNING, "Failed to start async wait\n");
07520 ast_free(as);
07521 if (channel) {
07522 *channel = NULL;
07523 ast_channel_unlock(chan);
07524 }
07525 ast_hangup(chan);
07526 res = -1;
07527 goto outgoing_exten_cleanup;
07528 }
07529 res = 0;
07530 }
07531 outgoing_exten_cleanup:
07532 ast_variables_destroy(vars);
07533 return res;
07534 }
07535
07536 struct app_tmp {
07537 char app[256];
07538 char data[256];
07539 struct ast_channel *chan;
07540 pthread_t t;
07541 };
07542
07543
07544 static void *ast_pbx_run_app(void *data)
07545 {
07546 struct app_tmp *tmp = data;
07547 struct ast_app *app;
07548 app = pbx_findapp(tmp->app);
07549 if (app) {
07550 ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
07551 pbx_exec(tmp->chan, app, tmp->data);
07552 } else
07553 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
07554 ast_hangup(tmp->chan);
07555 ast_free(tmp);
07556 return NULL;
07557 }
07558
07559 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)
07560 {
07561 struct ast_channel *chan;
07562 struct app_tmp *tmp;
07563 int res = -1, cdr_res = -1;
07564 struct outgoing_helper oh;
07565
07566 memset(&oh, 0, sizeof(oh));
07567 oh.vars = vars;
07568 oh.account = account;
07569
07570 if (locked_channel)
07571 *locked_channel = NULL;
07572 if (ast_strlen_zero(app)) {
07573 res = -1;
07574 goto outgoing_app_cleanup;
07575 }
07576 if (synchronous) {
07577 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07578 if (chan) {
07579 ast_set_variables(chan, vars);
07580 if (account)
07581 ast_cdr_setaccount(chan, account);
07582 if (chan->_state == AST_STATE_UP) {
07583 res = 0;
07584 ast_verb(4, "Channel %s was answered.\n", chan->name);
07585 tmp = ast_calloc(1, sizeof(*tmp));
07586 if (!tmp)
07587 res = -1;
07588 else {
07589 ast_copy_string(tmp->app, app, sizeof(tmp->app));
07590 if (appdata)
07591 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
07592 tmp->chan = chan;
07593 if (synchronous > 1) {
07594 if (locked_channel)
07595 ast_channel_unlock(chan);
07596 ast_pbx_run_app(tmp);
07597 } else {
07598 if (locked_channel)
07599 ast_channel_lock(chan);
07600 if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
07601 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
07602 ast_free(tmp);
07603 if (locked_channel)
07604 ast_channel_unlock(chan);
07605 ast_hangup(chan);
07606 res = -1;
07607 } else {
07608 if (locked_channel)
07609 *locked_channel = chan;
07610 }
07611 }
07612 }
07613 } else {
07614 ast_verb(4, "Channel %s was never answered.\n", chan->name);
07615 if (chan->cdr) {
07616
07617
07618 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07619 ast_cdr_failed(chan->cdr);
07620 }
07621 ast_hangup(chan);
07622 }
07623 }
07624
07625 if (res < 0) {
07626 if (*reason == 0) {
07627
07628 cdr_res = ast_pbx_outgoing_cdr_failed();
07629 if (cdr_res != 0) {
07630 res = cdr_res;
07631 goto outgoing_app_cleanup;
07632 }
07633 }
07634 }
07635
07636 } else {
07637 struct async_stat *as;
07638 if (!(as = ast_calloc(1, sizeof(*as)))) {
07639 res = -1;
07640 goto outgoing_app_cleanup;
07641 }
07642 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07643 if (!chan) {
07644 ast_free(as);
07645 res = -1;
07646 goto outgoing_app_cleanup;
07647 }
07648 as->chan = chan;
07649 ast_copy_string(as->app, app, sizeof(as->app));
07650 if (appdata)
07651 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
07652 as->timeout = timeout;
07653 ast_set_variables(chan, vars);
07654 if (account)
07655 ast_cdr_setaccount(chan, account);
07656
07657 if (locked_channel)
07658 ast_channel_lock(chan);
07659 if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07660 ast_log(LOG_WARNING, "Failed to start async wait\n");
07661 ast_free(as);
07662 if (locked_channel)
07663 ast_channel_unlock(chan);
07664 ast_hangup(chan);
07665 res = -1;
07666 goto outgoing_app_cleanup;
07667 } else {
07668 if (locked_channel)
07669 *locked_channel = chan;
07670 }
07671 res = 0;
07672 }
07673 outgoing_app_cleanup:
07674 ast_variables_destroy(vars);
07675 return res;
07676 }
07677
07678
07679
07680
07681
07682 static void __ast_internal_context_destroy( struct ast_context *con)
07683 {
07684 struct ast_include *tmpi;
07685 struct ast_sw *sw;
07686 struct ast_exten *e, *el, *en;
07687 struct ast_ignorepat *ipi;
07688 struct ast_context *tmp = con;
07689
07690 for (tmpi = tmp->includes; tmpi; ) {
07691 struct ast_include *tmpil = tmpi;
07692 tmpi = tmpi->next;
07693 ast_free(tmpil);
07694 }
07695 for (ipi = tmp->ignorepats; ipi; ) {
07696 struct ast_ignorepat *ipl = ipi;
07697 ipi = ipi->next;
07698 ast_free(ipl);
07699 }
07700 if (tmp->registrar)
07701 ast_free(tmp->registrar);
07702
07703
07704 if (tmp->root_table) {
07705 ast_hashtab_destroy(tmp->root_table, 0);
07706 }
07707
07708 if (tmp->pattern_tree)
07709 destroy_pattern_tree(tmp->pattern_tree);
07710
07711 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
07712 ast_free(sw);
07713 for (e = tmp->root; e;) {
07714 for (en = e->peer; en;) {
07715 el = en;
07716 en = en->peer;
07717 destroy_exten(el);
07718 }
07719 el = e;
07720 e = e->next;
07721 destroy_exten(el);
07722 }
07723 tmp->root = NULL;
07724 ast_rwlock_destroy(&tmp->lock);
07725 ast_free(tmp);
07726 }
07727
07728
07729 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
07730 {
07731 struct ast_context *tmp, *tmpl=NULL;
07732 struct ast_exten *exten_item, *prio_item;
07733
07734 for (tmp = list; tmp; ) {
07735 struct ast_context *next = NULL;
07736
07737
07738
07739
07740 ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
07741 if (con) {
07742 for (; tmp; tmpl = tmp, tmp = tmp->next) {
07743 ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
07744 if ( !strcasecmp(tmp->name, con->name) ) {
07745 break;
07746 }
07747 }
07748 }
07749
07750 if (!tmp)
07751 break;
07752 ast_wrlock_context(tmp);
07753
07754 if (registrar) {
07755
07756 struct ast_hashtab_iter *exten_iter;
07757 struct ast_hashtab_iter *prio_iter;
07758 struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
07759 struct ast_include *i, *pi = NULL, *ni = NULL;
07760 struct ast_sw *sw = NULL;
07761
07762
07763 for (ip = tmp->ignorepats; ip; ip = ipn) {
07764 ipn = ip->next;
07765 if (!strcmp(ip->registrar, registrar)) {
07766 if (ipl) {
07767 ipl->next = ip->next;
07768 ast_free(ip);
07769 continue;
07770 } else {
07771 tmp->ignorepats = ip->next;
07772 ast_free(ip);
07773 continue;
07774 }
07775 }
07776 ipl = ip;
07777 }
07778
07779 for (i = tmp->includes; i; i = ni) {
07780 ni = i->next;
07781 if (strcmp(i->registrar, registrar) == 0) {
07782
07783 if (pi) {
07784 pi->next = i->next;
07785
07786 ast_free(i);
07787 continue;
07788 } else {
07789 tmp->includes = i->next;
07790
07791 ast_free(i);
07792 continue;
07793 }
07794 }
07795 pi = i;
07796 }
07797
07798 AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
07799 if (strcmp(sw->registrar,registrar) == 0) {
07800 AST_LIST_REMOVE_CURRENT(list);
07801 ast_free(sw);
07802 }
07803 }
07804 AST_LIST_TRAVERSE_SAFE_END;
07805
07806 if (tmp->root_table) {
07807 exten_iter = ast_hashtab_start_traversal(tmp->root_table);
07808 while ((exten_item=ast_hashtab_next(exten_iter))) {
07809 prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
07810 while ((prio_item=ast_hashtab_next(prio_iter))) {
07811 if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
07812 continue;
07813 }
07814 ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
07815 tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
07816
07817 ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
07818 }
07819 ast_hashtab_end_traversal(prio_iter);
07820 }
07821 ast_hashtab_end_traversal(exten_iter);
07822 }
07823
07824
07825
07826
07827 if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
07828 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07829 ast_hashtab_remove_this_object(contexttab, tmp);
07830
07831 next = tmp->next;
07832 if (tmpl)
07833 tmpl->next = next;
07834 else
07835 contexts = next;
07836
07837
07838 ast_unlock_context(tmp);
07839 __ast_internal_context_destroy(tmp);
07840 } else {
07841 ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
07842 tmp->refcount, tmp->root);
07843 ast_unlock_context(tmp);
07844 next = tmp->next;
07845 tmpl = tmp;
07846 }
07847 } else if (con) {
07848 ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
07849 ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07850 ast_hashtab_remove_this_object(contexttab, tmp);
07851
07852 next = tmp->next;
07853 if (tmpl)
07854 tmpl->next = next;
07855 else
07856 contexts = next;
07857
07858
07859 ast_unlock_context(tmp);
07860 __ast_internal_context_destroy(tmp);
07861 }
07862
07863
07864 tmp = con ? NULL : next;
07865 }
07866 }
07867
07868 void ast_context_destroy(struct ast_context *con, const char *registrar)
07869 {
07870 ast_wrlock_contexts();
07871 __ast_context_destroy(contexts, contexts_table, con,registrar);
07872 ast_unlock_contexts();
07873 }
07874
07875 static void wait_for_hangup(struct ast_channel *chan, void *data)
07876 {
07877 int res;
07878 struct ast_frame *f;
07879 double waitsec;
07880 int waittime;
07881
07882 if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
07883 waitsec = -1;
07884 if (waitsec > -1) {
07885 waittime = waitsec * 1000.0;
07886 ast_safe_sleep(chan, waittime);
07887 } else do {
07888 res = ast_waitfor(chan, -1);
07889 if (res < 0)
07890 return;
07891 f = ast_read(chan);
07892 if (f)
07893 ast_frfree(f);
07894 } while(f);
07895 }
07896
07897
07898
07899
07900 static int pbx_builtin_proceeding(struct ast_channel *chan, void *data)
07901 {
07902 ast_indicate(chan, AST_CONTROL_PROCEEDING);
07903 return 0;
07904 }
07905
07906
07907
07908
07909 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
07910 {
07911 ast_indicate(chan, AST_CONTROL_PROGRESS);
07912 return 0;
07913 }
07914
07915
07916
07917
07918 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
07919 {
07920 ast_indicate(chan, AST_CONTROL_RINGING);
07921 return 0;
07922 }
07923
07924
07925
07926
07927 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
07928 {
07929 ast_indicate(chan, AST_CONTROL_BUSY);
07930
07931
07932 if (chan->_state != AST_STATE_UP) {
07933 ast_setstate(chan, AST_STATE_BUSY);
07934 ast_cdr_busy(chan->cdr);
07935 }
07936 wait_for_hangup(chan, data);
07937 return -1;
07938 }
07939
07940
07941
07942
07943 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
07944 {
07945 ast_indicate(chan, AST_CONTROL_CONGESTION);
07946
07947
07948 if (chan->_state != AST_STATE_UP)
07949 ast_setstate(chan, AST_STATE_BUSY);
07950 wait_for_hangup(chan, data);
07951 return -1;
07952 }
07953
07954
07955
07956
07957 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
07958 {
07959 int delay = 0;
07960
07961 if ((chan->_state != AST_STATE_UP) && !ast_strlen_zero(data))
07962 delay = atoi(data);
07963
07964 if (delay < 0) {
07965 delay = 0;
07966 }
07967
07968 return __ast_answer(chan, delay, 1);
07969 }
07970
07971 static int pbx_builtin_incomplete(struct ast_channel *chan, void *data)
07972 {
07973 char *options = data;
07974 int answer = 1;
07975
07976
07977 if (!ast_strlen_zero(options) && strchr(options, 'n')) {
07978 answer = 0;
07979 }
07980
07981
07982 if (ast_check_hangup(chan)) {
07983 return -1;
07984 } else if (chan->_state != AST_STATE_UP && answer) {
07985 __ast_answer(chan, 0, 1);
07986 }
07987
07988 return AST_PBX_INCOMPLETE;
07989 }
07990
07991 AST_APP_OPTIONS(resetcdr_opts, {
07992 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
07993 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
07994 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
07995 AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),
07996 });
07997
07998
07999
08000
08001 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
08002 {
08003 char *args;
08004 struct ast_flags flags = { 0 };
08005
08006 if (!ast_strlen_zero(data)) {
08007 args = ast_strdupa(data);
08008 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
08009 }
08010
08011 ast_cdr_reset(chan->cdr, &flags);
08012
08013 return 0;
08014 }
08015
08016
08017
08018
08019 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
08020 {
08021
08022 ast_cdr_setamaflags(chan, data ? data : "");
08023 return 0;
08024 }
08025
08026
08027
08028
08029 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
08030 {
08031 if (!ast_strlen_zero(data)) {
08032 int cause;
08033 char *endptr;
08034
08035 if ((cause = ast_str2cause(data)) > -1) {
08036 chan->hangupcause = cause;
08037 return -1;
08038 }
08039
08040 cause = strtol((const char *) data, &endptr, 10);
08041 if (cause != 0 || (data != endptr)) {
08042 chan->hangupcause = cause;
08043 return -1;
08044 }
08045
08046 ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
08047 }
08048
08049 if (!chan->hangupcause) {
08050 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
08051 }
08052
08053 return -1;
08054 }
08055
08056
08057
08058
08059 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
08060 {
08061 char *s, *ts, *branch1, *branch2, *branch;
08062 struct ast_timing timing;
08063
08064 if (ast_strlen_zero(data)) {
08065 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>?'labeliftrue':'labeliffalse'\n");
08066 return -1;
08067 }
08068
08069 ts = s = ast_strdupa(data);
08070
08071
08072 strsep(&ts, "?");
08073 branch1 = strsep(&ts,":");
08074 branch2 = strsep(&ts,"");
08075
08076
08077 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
08078 branch = branch1;
08079 else
08080 branch = branch2;
08081
08082 if (ast_strlen_zero(branch)) {
08083 ast_debug(1, "Not taking any branch\n");
08084 return 0;
08085 }
08086
08087 return pbx_builtin_goto(chan, branch);
08088 }
08089
08090
08091
08092
08093 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
08094 {
08095 char *s, *appname;
08096 struct ast_timing timing;
08097 struct ast_app *app;
08098 static const char *usage = "ExecIfTime requires an argument:\n <time range>,<days of week>,<days of month>,<months>?<appname>[(<appargs>)]";
08099
08100 if (ast_strlen_zero(data)) {
08101 ast_log(LOG_WARNING, "%s\n", usage);
08102 return -1;
08103 }
08104
08105 appname = ast_strdupa(data);
08106
08107 s = strsep(&appname, "?");
08108 if (!appname) {
08109 ast_log(LOG_WARNING, "%s\n", usage);
08110 return -1;
08111 }
08112
08113 if (!ast_build_timing(&timing, s)) {
08114 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
08115 return -1;
08116 }
08117
08118 if (!ast_check_timing(&timing))
08119 return 0;
08120
08121
08122 if ((s = strchr(appname, '('))) {
08123 char *e;
08124 *s++ = '\0';
08125 if ((e = strrchr(s, ')')))
08126 *e = '\0';
08127 else
08128 ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
08129 }
08130
08131
08132 if ((app = pbx_findapp(appname))) {
08133 return pbx_exec(chan, app, S_OR(s, ""));
08134 } else {
08135 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
08136 return -1;
08137 }
08138 }
08139
08140
08141
08142
08143 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
08144 {
08145 double s;
08146 int ms;
08147
08148
08149 if (data && (s = atof(data)) > 0.0) {
08150 ms = s * 1000.0;
08151 return ast_safe_sleep(chan, ms);
08152 }
08153 return 0;
08154 }
08155
08156
08157
08158
08159 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
08160 {
08161 int ms, res;
08162 double s;
08163 struct ast_flags flags = {0};
08164 char *opts[1] = { NULL };
08165 char *parse;
08166 AST_DECLARE_APP_ARGS(args,
08167 AST_APP_ARG(timeout);
08168 AST_APP_ARG(options);
08169 );
08170
08171 if (!ast_strlen_zero(data)) {
08172 parse = ast_strdupa(data);
08173 AST_STANDARD_APP_ARGS(args, parse);
08174 } else
08175 memset(&args, 0, sizeof(args));
08176
08177 if (args.options)
08178 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
08179
08180 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
08181 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
08182 } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
08183 ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL), strlen(opts[0]));
08184 } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
08185 const struct tone_zone_sound *ts = ast_get_indication_tone(chan->zone, "dial");
08186 if (ts)
08187 ast_playtones_start(chan, 0, ts->data, 0);
08188 else
08189 ast_tonepair_start(chan, 350, 440, 0, 0);
08190 }
08191
08192 if (args.timeout && (s = atof(args.timeout)) > 0)
08193 ms = s * 1000.0;
08194 else if (chan->pbx)
08195 ms = chan->pbx->rtimeoutms;
08196 else
08197 ms = 10000;
08198
08199 res = ast_waitfordigit(chan, ms);
08200 if (!res) {
08201 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
08202 ast_verb(3, "Timeout on %s, continuing...\n", chan->name);
08203 } else if (chan->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
08204 ast_verb(3, "Call timeout on %s, checking for 'T'\n", chan->name);
08205 res = -1;
08206 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
08207 ast_verb(3, "Timeout on %s, going to 't'\n", chan->name);
08208 set_ext_pri(chan, "t", 0);
08209 } else {
08210 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
08211 res = -1;
08212 }
08213 }
08214
08215 if (ast_test_flag(&flags, WAITEXTEN_MOH))
08216 ast_indicate(chan, AST_CONTROL_UNHOLD);
08217 else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
08218 ast_playtones_stop(chan);
08219
08220 return res;
08221 }
08222
08223
08224
08225
08226 static int pbx_builtin_background(struct ast_channel *chan, void *data)
08227 {
08228 int res = 0;
08229 int mres = 0;
08230 struct ast_flags flags = {0};
08231 char *parse, exten[2] = "";
08232 AST_DECLARE_APP_ARGS(args,
08233 AST_APP_ARG(filename);
08234 AST_APP_ARG(options);
08235 AST_APP_ARG(lang);
08236 AST_APP_ARG(context);
08237 );
08238
08239 if (ast_strlen_zero(data)) {
08240 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
08241 return -1;
08242 }
08243
08244 parse = ast_strdupa(data);
08245
08246 AST_STANDARD_APP_ARGS(args, parse);
08247
08248 if (ast_strlen_zero(args.lang))
08249 args.lang = (char *)chan->language;
08250
08251 if (ast_strlen_zero(args.context)) {
08252 const char *context;
08253 ast_channel_lock(chan);
08254 if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
08255 args.context = ast_strdupa(context);
08256 } else {
08257 args.context = chan->context;
08258 }
08259 ast_channel_unlock(chan);
08260 }
08261
08262 if (args.options) {
08263 if (!strcasecmp(args.options, "skip"))
08264 flags.flags = BACKGROUND_SKIP;
08265 else if (!strcasecmp(args.options, "noanswer"))
08266 flags.flags = BACKGROUND_NOANSWER;
08267 else
08268 ast_app_parse_options(background_opts, &flags, NULL, args.options);
08269 }
08270
08271
08272 if (chan->_state != AST_STATE_UP) {
08273 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
08274 goto done;
08275 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
08276 res = ast_answer(chan);
08277 }
08278 }
08279
08280 if (!res) {
08281 char *back = args.filename;
08282 char *front;
08283
08284 ast_stopstream(chan);
08285
08286 while (!res && (front = strsep(&back, "&")) ) {
08287 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
08288 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
08289 res = 0;
08290 mres = 1;
08291 break;
08292 }
08293 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
08294 res = ast_waitstream(chan, "");
08295 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
08296 res = ast_waitstream_exten(chan, args.context);
08297 } else {
08298 res = ast_waitstream(chan, AST_DIGIT_ANY);
08299 }
08300 ast_stopstream(chan);
08301 }
08302 }
08303
08304
08305
08306
08307
08308
08309
08310
08311
08312
08313
08314
08315
08316
08317
08318
08319
08320
08321
08322 if (!ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS) &&
08323 (exten[0] = res) &&
08324 ast_canmatch_extension(chan, args.context, exten, 1, chan->cid.cid_num) &&
08325 !ast_matchmore_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
08326 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
08327 ast_copy_string(chan->context, args.context, sizeof(chan->context));
08328 chan->priority = 0;
08329 res = 0;
08330 }
08331 done:
08332 pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
08333 return res;
08334 }
08335
08336
08337
08338
08339 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
08340 {
08341 int res = ast_parseable_goto(chan, data);
08342 if (!res)
08343 ast_verb(3, "Goto (%s,%s,%d)\n", chan->context, chan->exten, chan->priority + 1);
08344 return res;
08345 }
08346
08347
08348 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
08349 {
08350 struct ast_var_t *variables;
08351 const char *var, *val;
08352 int total = 0;
08353
08354 if (!chan)
08355 return 0;
08356
08357 (*buf)->used = 0;
08358 (*buf)->str[0] = '\0';
08359
08360 ast_channel_lock(chan);
08361
08362 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
08363 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
08364
08365 ) {
08366 if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
08367 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
08368 break;
08369 } else
08370 total++;
08371 } else
08372 break;
08373 }
08374
08375 ast_channel_unlock(chan);
08376
08377 return total;
08378 }
08379
08380 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
08381 {
08382 struct ast_var_t *variables;
08383 const char *ret = NULL;
08384 int i;
08385 struct varshead *places[2] = { NULL, &globals };
08386
08387 if (!name)
08388 return NULL;
08389
08390 if (chan) {
08391 ast_channel_lock(chan);
08392 places[0] = &chan->varshead;
08393 }
08394
08395 for (i = 0; i < 2; i++) {
08396 if (!places[i])
08397 continue;
08398 if (places[i] == &globals)
08399 ast_rwlock_rdlock(&globalslock);
08400 AST_LIST_TRAVERSE(places[i], variables, entries) {
08401 if (!strcmp(name, ast_var_name(variables))) {
08402 ret = ast_var_value(variables);
08403 break;
08404 }
08405 }
08406 if (places[i] == &globals)
08407 ast_rwlock_unlock(&globalslock);
08408 if (ret)
08409 break;
08410 }
08411
08412 if (chan)
08413 ast_channel_unlock(chan);
08414
08415 return ret;
08416 }
08417
08418 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
08419 {
08420 struct ast_var_t *newvariable;
08421 struct varshead *headp;
08422
08423 if (name[strlen(name)-1] == ')') {
08424 char *function = ast_strdupa(name);
08425
08426 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
08427 ast_func_write(chan, function, value);
08428 return;
08429 }
08430
08431 if (chan) {
08432 ast_channel_lock(chan);
08433 headp = &chan->varshead;
08434 } else {
08435 ast_rwlock_wrlock(&globalslock);
08436 headp = &globals;
08437 }
08438
08439 if (value) {
08440 if (headp == &globals)
08441 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08442 newvariable = ast_var_assign(name, value);
08443 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08444 }
08445
08446 if (chan)
08447 ast_channel_unlock(chan);
08448 else
08449 ast_rwlock_unlock(&globalslock);
08450 }
08451
08452 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
08453 {
08454 struct ast_var_t *newvariable;
08455 struct varshead *headp;
08456 const char *nametail = name;
08457
08458 if (name[strlen(name) - 1] == ')') {
08459 char *function = ast_strdupa(name);
08460
08461 ast_func_write(chan, function, value);
08462 return;
08463 }
08464
08465 if (chan) {
08466 ast_channel_lock(chan);
08467 headp = &chan->varshead;
08468 } else {
08469 ast_rwlock_wrlock(&globalslock);
08470 headp = &globals;
08471 }
08472
08473
08474 if (*nametail == '_') {
08475 nametail++;
08476 if (*nametail == '_')
08477 nametail++;
08478 }
08479
08480 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
08481 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
08482
08483 AST_LIST_REMOVE_CURRENT(entries);
08484 ast_var_delete(newvariable);
08485 break;
08486 }
08487 }
08488 AST_LIST_TRAVERSE_SAFE_END;
08489
08490 if (value) {
08491 if (headp == &globals)
08492 ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08493 newvariable = ast_var_assign(name, value);
08494 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08495 manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
08496 "Channel: %s\r\n"
08497 "Variable: %s\r\n"
08498 "Value: %s\r\n"
08499 "Uniqueid: %s\r\n",
08500 chan ? chan->name : "none", name, value,
08501 chan ? chan->uniqueid : "none");
08502 }
08503
08504 if (chan)
08505 ast_channel_unlock(chan);
08506 else
08507 ast_rwlock_unlock(&globalslock);
08508 }
08509
08510 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
08511 {
08512 char *name, *value, *mydata;
08513
08514 if (ast_compat_app_set) {
08515 return pbx_builtin_setvar_multiple(chan, data);
08516 }
08517
08518 if (ast_strlen_zero(data)) {
08519 ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
08520 return 0;
08521 }
08522
08523 mydata = ast_strdupa(data);
08524 name = strsep(&mydata, "=");
08525 value = mydata;
08526 if (strchr(name, ' '))
08527 ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
08528
08529 pbx_builtin_setvar_helper(chan, name, value);
08530 return(0);
08531 }
08532
08533 int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *vdata)
08534 {
08535 char *data;
08536 int x;
08537 AST_DECLARE_APP_ARGS(args,
08538 AST_APP_ARG(pair)[24];
08539 );
08540 AST_DECLARE_APP_ARGS(pair,
08541 AST_APP_ARG(name);
08542 AST_APP_ARG(value);
08543 );
08544
08545 if (ast_strlen_zero(vdata)) {
08546 ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
08547 return 0;
08548 }
08549
08550 data = ast_strdupa(vdata);
08551 AST_STANDARD_APP_ARGS(args, data);
08552
08553 for (x = 0; x < args.argc; x++) {
08554 AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
08555 if (pair.argc == 2) {
08556 pbx_builtin_setvar_helper(chan, pair.name, pair.value);
08557 if (strchr(pair.name, ' '))
08558 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);
08559 } else if (!chan) {
08560 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
08561 } else {
08562 ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
08563 }
08564 }
08565
08566 return 0;
08567 }
08568
08569 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
08570 {
08571 char *name;
08572 char *value;
08573 char *channel;
08574 char tmp[VAR_BUF_SIZE];
08575 static int deprecation_warning = 0;
08576
08577 if (ast_strlen_zero(data)) {
08578 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
08579 return 0;
08580 }
08581 tmp[0] = 0;
08582 if (!deprecation_warning) {
08583 ast_log(LOG_WARNING, "ImportVar is deprecated. Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
08584 deprecation_warning = 1;
08585 }
08586
08587 value = ast_strdupa(data);
08588 name = strsep(&value,"=");
08589 channel = strsep(&value,",");
08590 if (channel && value && name) {
08591 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
08592 if (chan2) {
08593 char *s = alloca(strlen(value) + 4);
08594 if (s) {
08595 sprintf(s, "${%s}", value);
08596 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
08597 }
08598 ast_channel_unlock(chan2);
08599 }
08600 pbx_builtin_setvar_helper(chan, name, tmp);
08601 }
08602
08603 return(0);
08604 }
08605
08606 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
08607 {
08608 return 0;
08609 }
08610
08611 void pbx_builtin_clear_globals(void)
08612 {
08613 struct ast_var_t *vardata;
08614
08615 ast_rwlock_wrlock(&globalslock);
08616 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
08617 ast_var_delete(vardata);
08618 ast_rwlock_unlock(&globalslock);
08619 }
08620
08621 int pbx_checkcondition(const char *condition)
08622 {
08623 int res;
08624 if (ast_strlen_zero(condition)) {
08625 return 0;
08626 } else if (sscanf(condition, "%30d", &res) == 1) {
08627 return res;
08628 } else {
08629 return 1;
08630 }
08631 }
08632
08633 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
08634 {
08635 char *condition, *branch1, *branch2, *branch;
08636 char *stringp;
08637
08638 if (ast_strlen_zero(data)) {
08639 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
08640 return 0;
08641 }
08642
08643 stringp = ast_strdupa(data);
08644 condition = strsep(&stringp,"?");
08645 branch1 = strsep(&stringp,":");
08646 branch2 = strsep(&stringp,"");
08647 branch = pbx_checkcondition(condition) ? branch1 : branch2;
08648
08649 if (ast_strlen_zero(branch)) {
08650 ast_debug(1, "Not taking any branch\n");
08651 return 0;
08652 }
08653
08654 return pbx_builtin_goto(chan, branch);
08655 }
08656
08657 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
08658 {
08659 char tmp[256];
08660 char *number = tmp;
08661 char *options;
08662
08663 if (ast_strlen_zero(data)) {
08664 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
08665 return -1;
08666 }
08667 ast_copy_string(tmp, data, sizeof(tmp));
08668 strsep(&number, ",");
08669 options = strsep(&number, ",");
08670 if (options) {
08671 if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
08672 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
08673 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
08674 return -1;
08675 }
08676 }
08677
08678 if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
08679 ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
08680 }
08681
08682 return 0;
08683 }
08684
08685 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
08686 {
08687 int res = 0;
08688
08689 if (data)
08690 res = ast_say_digit_str(chan, data, "", chan->language);
08691 return res;
08692 }
08693
08694 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
08695 {
08696 int res = 0;
08697
08698 if (data)
08699 res = ast_say_character_str(chan, data, "", chan->language);
08700 return res;
08701 }
08702
08703 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
08704 {
08705 int res = 0;
08706
08707 if (data)
08708 res = ast_say_phonetic_str(chan, data, "", chan->language);
08709 return res;
08710 }
08711
08712 static void device_state_cb(const struct ast_event *event, void *unused)
08713 {
08714 const char *device;
08715 struct statechange *sc;
08716
08717 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
08718 if (ast_strlen_zero(device)) {
08719 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
08720 return;
08721 }
08722
08723 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
08724 return;
08725 strcpy(sc->dev, device);
08726 if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
08727 ast_free(sc);
08728 }
08729 }
08730
08731 int load_pbx(void)
08732 {
08733 int x;
08734
08735
08736 ast_verb(1, "Asterisk PBX Core Initializing\n");
08737 if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
08738 ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
08739 }
08740
08741 ast_verb(1, "Registering builtin applications:\n");
08742 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
08743 __ast_custom_function_register(&exception_function, NULL);
08744
08745
08746 for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
08747 ast_verb(1, "[%s]\n", builtins[x].name);
08748 if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) {
08749 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
08750 return -1;
08751 }
08752 }
08753
08754
08755 ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
08756
08757 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
08758 AST_EVENT_IE_END))) {
08759 return -1;
08760 }
08761
08762 return 0;
08763 }
08764 static int conlock_wrlock_version = 0;
08765
08766 int ast_wrlock_contexts_version(void)
08767 {
08768 return conlock_wrlock_version;
08769 }
08770
08771
08772
08773
08774 int ast_wrlock_contexts()
08775 {
08776 int res = ast_rwlock_wrlock(&conlock);
08777 if (!res)
08778 ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
08779 return res;
08780 }
08781
08782 int ast_rdlock_contexts()
08783 {
08784 return ast_rwlock_rdlock(&conlock);
08785 }
08786
08787 int ast_unlock_contexts()
08788 {
08789 return ast_rwlock_unlock(&conlock);
08790 }
08791
08792
08793
08794
08795 int ast_wrlock_context(struct ast_context *con)
08796 {
08797 return ast_rwlock_wrlock(&con->lock);
08798 }
08799
08800 int ast_rdlock_context(struct ast_context *con)
08801 {
08802 return ast_rwlock_rdlock(&con->lock);
08803 }
08804
08805 int ast_unlock_context(struct ast_context *con)
08806 {
08807 return ast_rwlock_unlock(&con->lock);
08808 }
08809
08810
08811
08812
08813 const char *ast_get_context_name(struct ast_context *con)
08814 {
08815 return con ? con->name : NULL;
08816 }
08817
08818 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
08819 {
08820 return exten ? exten->parent : NULL;
08821 }
08822
08823 const char *ast_get_extension_name(struct ast_exten *exten)
08824 {
08825 return exten ? exten->exten : NULL;
08826 }
08827
08828 const char *ast_get_extension_label(struct ast_exten *exten)
08829 {
08830 return exten ? exten->label : NULL;
08831 }
08832
08833 const char *ast_get_include_name(struct ast_include *inc)
08834 {
08835 return inc ? inc->name : NULL;
08836 }
08837
08838 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
08839 {
08840 return ip ? ip->pattern : NULL;
08841 }
08842
08843 int ast_get_extension_priority(struct ast_exten *exten)
08844 {
08845 return exten ? exten->priority : -1;
08846 }
08847
08848
08849
08850
08851 const char *ast_get_context_registrar(struct ast_context *c)
08852 {
08853 return c ? c->registrar : NULL;
08854 }
08855
08856 const char *ast_get_extension_registrar(struct ast_exten *e)
08857 {
08858 return e ? e->registrar : NULL;
08859 }
08860
08861 const char *ast_get_include_registrar(struct ast_include *i)
08862 {
08863 return i ? i->registrar : NULL;
08864 }
08865
08866 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
08867 {
08868 return ip ? ip->registrar : NULL;
08869 }
08870
08871 int ast_get_extension_matchcid(struct ast_exten *e)
08872 {
08873 return e ? e->matchcid : 0;
08874 }
08875
08876 const char *ast_get_extension_cidmatch(struct ast_exten *e)
08877 {
08878 return e ? e->cidmatch : NULL;
08879 }
08880
08881 const char *ast_get_extension_app(struct ast_exten *e)
08882 {
08883 return e ? e->app : NULL;
08884 }
08885
08886 void *ast_get_extension_app_data(struct ast_exten *e)
08887 {
08888 return e ? e->data : NULL;
08889 }
08890
08891 const char *ast_get_switch_name(struct ast_sw *sw)
08892 {
08893 return sw ? sw->name : NULL;
08894 }
08895
08896 const char *ast_get_switch_data(struct ast_sw *sw)
08897 {
08898 return sw ? sw->data : NULL;
08899 }
08900
08901 int ast_get_switch_eval(struct ast_sw *sw)
08902 {
08903 return sw->eval;
08904 }
08905
08906 const char *ast_get_switch_registrar(struct ast_sw *sw)
08907 {
08908 return sw ? sw->registrar : NULL;
08909 }
08910
08911
08912
08913
08914 struct ast_context *ast_walk_contexts(struct ast_context *con)
08915 {
08916 return con ? con->next : contexts;
08917 }
08918
08919 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
08920 struct ast_exten *exten)
08921 {
08922 if (!exten)
08923 return con ? con->root : NULL;
08924 else
08925 return exten->next;
08926 }
08927
08928 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
08929 struct ast_sw *sw)
08930 {
08931 if (!sw)
08932 return con ? AST_LIST_FIRST(&con->alts) : NULL;
08933 else
08934 return AST_LIST_NEXT(sw, list);
08935 }
08936
08937 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
08938 struct ast_exten *priority)
08939 {
08940 return priority ? priority->peer : exten;
08941 }
08942
08943 struct ast_include *ast_walk_context_includes(struct ast_context *con,
08944 struct ast_include *inc)
08945 {
08946 if (!inc)
08947 return con ? con->includes : NULL;
08948 else
08949 return inc->next;
08950 }
08951
08952 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
08953 struct ast_ignorepat *ip)
08954 {
08955 if (!ip)
08956 return con ? con->ignorepats : NULL;
08957 else
08958 return ip->next;
08959 }
08960
08961 int ast_context_verify_includes(struct ast_context *con)
08962 {
08963 struct ast_include *inc = NULL;
08964 int res = 0;
08965
08966 while ( (inc = ast_walk_context_includes(con, inc)) ) {
08967 if (ast_context_find(inc->rname))
08968 continue;
08969
08970 res = -1;
08971 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
08972 ast_get_context_name(con), inc->rname);
08973 break;
08974 }
08975
08976 return res;
08977 }
08978
08979
08980 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
08981 {
08982 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
08983
08984 if (!chan)
08985 return -2;
08986
08987 if (context == NULL)
08988 context = chan->context;
08989 if (exten == NULL)
08990 exten = chan->exten;
08991
08992 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
08993 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
08994 return goto_func(chan, context, exten, priority);
08995 else
08996 return -3;
08997 }
08998
08999 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
09000 {
09001 return __ast_goto_if_exists(chan, context, exten, priority, 0);
09002 }
09003
09004 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
09005 {
09006 return __ast_goto_if_exists(chan, context, exten, priority, 1);
09007 }
09008
09009 static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
09010 {
09011 char *exten, *pri, *context;
09012 char *stringp;
09013 int ipri;
09014 int mode = 0;
09015
09016 if (ast_strlen_zero(goto_string)) {
09017 ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
09018 return -1;
09019 }
09020 stringp = ast_strdupa(goto_string);
09021 context = strsep(&stringp, ",");
09022 exten = strsep(&stringp, ",");
09023 pri = strsep(&stringp, ",");
09024 if (!exten) {
09025 pri = context;
09026 exten = NULL;
09027 context = NULL;
09028 } else if (!pri) {
09029 pri = exten;
09030 exten = context;
09031 context = NULL;
09032 }
09033 if (*pri == '+') {
09034 mode = 1;
09035 pri++;
09036 } else if (*pri == '-') {
09037 mode = -1;
09038 pri++;
09039 }
09040 if (sscanf(pri, "%30d", &ipri) != 1) {
09041 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
09042 pri, chan->cid.cid_num)) < 1) {
09043 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
09044 return -1;
09045 } else
09046 mode = 0;
09047 }
09048
09049
09050 if (mode)
09051 ipri = chan->priority + (ipri * mode);
09052
09053 if (async)
09054 ast_async_goto(chan, context, exten, ipri);
09055 else
09056 ast_explicit_goto(chan, context, exten, ipri);
09057
09058 return 0;
09059
09060 }
09061
09062 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
09063 {
09064 return pbx_parseable_goto(chan, goto_string, 0);
09065 }
09066
09067 int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
09068 {
09069 return pbx_parseable_goto(chan, goto_string, 1);
09070 }