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