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