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