Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

pbx.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Core PBX routines. 00005 * 00006 * Copyright (C) 1999, Mark Spencer 00007 * 00008 * Mark Spencer <markster@digium.com> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 00012 */ 00013 00014 #include <asterisk/lock.h> 00015 #include <asterisk/cli.h> 00016 #include <asterisk/pbx.h> 00017 #include <asterisk/channel.h> 00018 #include <asterisk/options.h> 00019 #include <asterisk/logger.h> 00020 #include <asterisk/file.h> 00021 #include <asterisk/callerid.h> 00022 #include <asterisk/cdr.h> 00023 #include <asterisk/config.h> 00024 #include <asterisk/term.h> 00025 #include <asterisk/manager.h> 00026 #include <asterisk/ast_expr.h> 00027 #include <asterisk/channel_pvt.h> 00028 #include <asterisk/linkedlists.h> 00029 #include <asterisk/say.h> 00030 #include <asterisk/utils.h> 00031 #include <string.h> 00032 #include <unistd.h> 00033 #include <stdlib.h> 00034 #include <stdio.h> 00035 #include <setjmp.h> 00036 #include <ctype.h> 00037 #include <errno.h> 00038 #include <time.h> 00039 #include <sys/time.h> 00040 #include "asterisk.h" 00041 00042 /* 00043 * I M P O R T A N T : 00044 * 00045 * The speed of extension handling will likely be among the most important 00046 * aspects of this PBX. The switching scheme as it exists right now isn't 00047 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg # 00048 * of priorities, but a constant search time here would be great ;-) 00049 * 00050 */ 00051 00052 #ifdef LOW_MEMORY 00053 #define EXT_DATA_SIZE 256 00054 #else 00055 #define EXT_DATA_SIZE 8192 00056 #endif 00057 00058 struct ast_context; 00059 00060 /* ast_exten: An extension */ 00061 struct ast_exten { 00062 char exten[AST_MAX_EXTENSION]; /* Extension name */ 00063 int matchcid; /* Match caller id ? */ 00064 char cidmatch[AST_MAX_EXTENSION]; /* Caller id to match for this extension */ 00065 int priority; /* Priority */ 00066 struct ast_context *parent; /* An extension */ 00067 char app[AST_MAX_EXTENSION]; /* Application to execute */ 00068 void *data; /* Data to use */ 00069 void (*datad)(void *); /* Data destructor */ 00070 struct ast_exten *peer; /* Next higher priority with our extension */ 00071 char *registrar; /* Registrar */ 00072 struct ast_exten *next; /* Extension with a greater ID */ 00073 }; 00074 00075 /* ast_include: include= support in extensions.conf */ 00076 struct ast_include { 00077 char name[AST_MAX_EXTENSION]; 00078 char rname[AST_MAX_EXTENSION]; /* Context to include */ 00079 char *registrar; /* Registrar */ 00080 int hastime; /* If time construct exists */ 00081 unsigned int monthmask; /* Mask for month */ 00082 unsigned int daymask; /* Mask for date */ 00083 unsigned int dowmask; /* Mask for day of week (mon-sun) */ 00084 unsigned int minmask[24]; /* Mask for minute */ 00085 struct ast_include *next; /* Link them together */ 00086 }; 00087 00088 /* ast_sw: Switch statement in extensions.conf */ 00089 struct ast_sw { 00090 char name[AST_MAX_EXTENSION]; 00091 char *registrar; /* Registrar */ 00092 char data[AST_MAX_EXTENSION]; /* Data load */ 00093 struct ast_sw *next; /* Link them together */ 00094 }; 00095 00096 struct ast_ignorepat { 00097 char pattern[AST_MAX_EXTENSION]; 00098 char *registrar; 00099 struct ast_ignorepat *next; 00100 }; 00101 00102 /* ast_context: An extension context */ 00103 struct ast_context { 00104 char name[AST_MAX_EXTENSION]; /* Name of the context */ 00105 ast_mutex_t lock; /* A lock to prevent multiple threads from clobbering the context */ 00106 struct ast_exten *root; /* The root of the list of extensions */ 00107 struct ast_context *next; /* Link them together */ 00108 struct ast_include *includes; /* Include other contexts */ 00109 struct ast_ignorepat *ignorepats; /* Patterns for which to continue playing dialtone */ 00110 char *registrar; /* Registrar */ 00111 struct ast_sw *alts; /* Alternative switches */ 00112 }; 00113 00114 00115 /* ast_app: An application */ 00116 struct ast_app { 00117 char name[AST_MAX_APP]; /* Name of the application */ 00118 int (*execute)(struct ast_channel *chan, void *data); 00119 char *synopsis; /* Synopsis text for 'show applications' */ 00120 char *description; /* Description (help text) for 'show application <name>' */ 00121 struct ast_app *next; /* Next app in list */ 00122 }; 00123 00124 /* ast_state_cb: An extension state notify */ 00125 struct ast_state_cb { 00126 int id; 00127 void *data; 00128 ast_state_cb_type callback; 00129 struct ast_state_cb *next; 00130 }; 00131 00132 struct ast_hint { 00133 struct ast_exten *exten; 00134 int laststate; 00135 struct ast_state_cb *callbacks; 00136 struct ast_hint *next; 00137 }; 00138 00139 00140 static int pbx_builtin_prefix(struct ast_channel *, void *); 00141 static int pbx_builtin_suffix(struct ast_channel *, void *); 00142 static int pbx_builtin_stripmsd(struct ast_channel *, void *); 00143 static int pbx_builtin_answer(struct ast_channel *, void *); 00144 static int pbx_builtin_goto(struct ast_channel *, void *); 00145 static int pbx_builtin_hangup(struct ast_channel *, void *); 00146 static int pbx_builtin_background(struct ast_channel *, void *); 00147 static int pbx_builtin_dtimeout(struct ast_channel *, void *); 00148 static int pbx_builtin_rtimeout(struct ast_channel *, void *); 00149 static int pbx_builtin_atimeout(struct ast_channel *, void *); 00150 static int pbx_builtin_wait(struct ast_channel *, void *); 00151 static int pbx_builtin_waitexten(struct ast_channel *, void *); 00152 static int pbx_builtin_setlanguage(struct ast_channel *, void *); 00153 static int pbx_builtin_resetcdr(struct ast_channel *, void *); 00154 static int pbx_builtin_setaccount(struct ast_channel *, void *); 00155 static int pbx_builtin_setamaflags(struct ast_channel *, void *); 00156 static int pbx_builtin_ringing(struct ast_channel *, void *); 00157 static int pbx_builtin_progress(struct ast_channel *, void *); 00158 static int pbx_builtin_congestion(struct ast_channel *, void *); 00159 static int pbx_builtin_busy(struct ast_channel *, void *); 00160 static int pbx_builtin_setglobalvar(struct ast_channel *, void *); 00161 static int pbx_builtin_noop(struct ast_channel *, void *); 00162 static int pbx_builtin_gotoif(struct ast_channel *, void *); 00163 static int pbx_builtin_gotoiftime(struct ast_channel *, void *); 00164 static int pbx_builtin_saynumber(struct ast_channel *, void *); 00165 static int pbx_builtin_saydigits(struct ast_channel *, void *); 00166 static int pbx_builtin_saycharacters(struct ast_channel *, void *); 00167 static int pbx_builtin_sayphonetic(struct ast_channel *, void *); 00168 int pbx_builtin_setvar(struct ast_channel *, void *); 00169 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value); 00170 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name); 00171 00172 static struct varshead globals; 00173 00174 static struct pbx_builtin { 00175 char name[AST_MAX_APP]; 00176 int (*execute)(struct ast_channel *chan, void *data); 00177 char *synopsis; 00178 char *description; 00179 } builtins[] = 00180 { 00181 /* These applications are built into the PBX core and do not 00182 need separate modules 00183 00184 */ 00185 00186 { "AbsoluteTimeout", pbx_builtin_atimeout, 00187 "Set absolute maximum time of call", 00188 " AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n" 00189 "for a call. A setting of 0 disables the timeout. Always returns 0.\n" 00190 }, 00191 00192 { "Answer", pbx_builtin_answer, 00193 "Answer a channel if ringing", 00194 " Answer(): If the channel is ringing, answer it, otherwise do nothing. \n" 00195 "Returns 0 unless it tries to answer the channel and fails.\n" 00196 }, 00197 00198 { "BackGround", pbx_builtin_background, 00199 "Play a file while awaiting extension", 00200 " Background(filename): Plays a given file, while simultaneously waiting for\n" 00201 "the user to begin typing an extension. The timeouts do not count until the\n" 00202 "last BackGround application has ended. Always returns 0.\n" 00203 }, 00204 00205 { "Busy", pbx_builtin_busy, 00206 "Indicate busy condition and stop", 00207 " Busy([timeout]): Requests that the channel indicate busy condition and\n" 00208 "then waits for the user to hang up or the optional timeout to expire.\n" 00209 "Always returns -1." 00210 }, 00211 00212 { "Congestion", pbx_builtin_congestion, 00213 "Indicate congestion and stop", 00214 " Congestion([timeout]): Requests that the channel indicate congestion\n" 00215 "and then waits for the user to hang up or for the optional timeout to\n" 00216 "expire. Always returns -1." 00217 }, 00218 00219 { "DigitTimeout", pbx_builtin_dtimeout, 00220 "Set maximum timeout between digits", 00221 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n" 00222 "digits when the user is typing in an extension. When this timeout expires,\n" 00223 "after the user has started to type in an extension, the extension will be\n" 00224 "considered complete, and will be interpreted. Note that if an extension\n" 00225 "typed in is valid, it will not have to timeout to be tested, so typically\n" 00226 "at the expiry of this timeout, the extension will be considered invalid\n" 00227 "(and thus control would be passed to the 'i' extension, or if it doesn't\n" 00228 "exist the call would be terminated). Always returns 0.\n" 00229 }, 00230 00231 { "Goto", pbx_builtin_goto, 00232 "Goto a particular priority, extension, or context", 00233 " Goto([[context|]extension|]priority): Set the priority to the specified\n" 00234 "value, optionally setting the extension and optionally the context as well.\n" 00235 "The extension BYEXTENSION is special in that it uses the current extension,\n" 00236 "thus permitting you to go to a different context, without specifying a\n" 00237 "specific extension. Always returns 0, even if the given context, extension,\n" 00238 "or priority is invalid.\n" 00239 }, 00240 00241 { "GotoIf", pbx_builtin_gotoif, 00242 "Conditional goto", 00243 " GotoIf(Condition?label1:label2): Go to label 1 if condition is\n" 00244 "true, to label2 if condition is false. Either label1 or label2 may be\n" 00245 "omitted (in that case, we just don't take the particular branch) but not\n" 00246 "both. Look for the condition syntax in examples or documentation." 00247 }, 00248 00249 { "GotoIfTime", pbx_builtin_gotoiftime, 00250 "Conditional goto on current time", 00251 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n" 00252 "If the current time matches the specified time, then branch to the specified\n" 00253 "extension. Each of the elements may be specified either as '*' (for always)\n" 00254 "or as a range. See the 'include' syntax for details." 00255 }, 00256 00257 { "Hangup", pbx_builtin_hangup, 00258 "Unconditional hangup", 00259 " Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" 00260 }, 00261 00262 { "NoOp", pbx_builtin_noop, 00263 "No operation", 00264 " NoOp(): No-operation; Does nothing." 00265 }, 00266 00267 { "Prefix", pbx_builtin_prefix, 00268 "Prepend leading digits", 00269 " Prefix(digits): Prepends the digit string specified by digits to the\n" 00270 "channel's associated extension. For example, the number 1212 when prefixed\n" 00271 "with '555' will become 5551212. This app always returns 0, and the PBX will\n" 00272 "continue processing at the next priority for the *new* extension.\n" 00273 " So, for example, if priority 3 of 1212 is Prefix 555, the next step\n" 00274 "executed will be priority 4 of 5551212. If you switch into an extension\n" 00275 "which has no first step, the PBX will treat it as though the user dialed an\n" 00276 "invalid extension.\n" 00277 }, 00278 00279 { "Progress", pbx_builtin_progress, 00280 "Indicate progress", 00281 " Progress(): Request that the channel indicate in-band progress is \n" 00282 "available to the user.\nAlways returns 0.\n" 00283 }, 00284 00285 { "ResetCDR", pbx_builtin_resetcdr, 00286 "Resets the Call Data Record", 00287 " ResetCDR([options]): Causes the Call Data Record to be reset, optionally\n" 00288 "storing the current CDR before zeroing it out (if 'w' option is specifed).\n" 00289 "record WILL be stored.\nAlways returns 0.\n" 00290 }, 00291 00292 { "ResponseTimeout", pbx_builtin_rtimeout, 00293 "Set maximum timeout awaiting response", 00294 " ResponseTimeout(seconds): Set the maximum amount of time permitted after\n" 00295 "falling through a series of priorities for a channel in which the user may\n" 00296 "begin typing an extension. If the user does not type an extension in this\n" 00297 "amount of time, control will pass to the 't' extension if it exists, and\n" 00298 "if not the call would be terminated.\nAlways returns 0.\n" 00299 }, 00300 00301 { "Ringing", pbx_builtin_ringing, 00302 "Indicate ringing tone", 00303 " Ringing(): Request that the channel indicate ringing tone to the user.\n" 00304 "Always returns 0.\n" 00305 }, 00306 00307 { "SayNumber", pbx_builtin_saynumber, 00308 "Say Number", 00309 " SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n" 00310 "the current language setting for the channel. (See app SetLanguage).\n" 00311 }, 00312 00313 { "SayDigits", pbx_builtin_saydigits, 00314 "Say Digits", 00315 " SayDigits(digits): Says the passed digits. SayDigits is using the\n" 00316 "current language setting for the channel. (See app setLanguage)\n" 00317 }, 00318 00319 { "SayAlpha", pbx_builtin_saycharacters, 00320 "Say Alpha", 00321 " SayAlpha(string): Spells the passed string\n" 00322 }, 00323 00324 { "SayPhonetic", pbx_builtin_sayphonetic, 00325 "Say Phonetic", 00326 " SayPhonetic(string): Spells the passed string with phonetic alphabet\n" 00327 }, 00328 00329 { "SetAccount", pbx_builtin_setaccount, 00330 "Sets account code", 00331 " SetAccount([account]): Set the channel account code for billing\n" 00332 "purposes. Always returns 0.\n" 00333 }, 00334 00335 { "SetAMAFlags", pbx_builtin_setamaflags, 00336 "Sets AMA Flags", 00337 " SetAMAFlags([flag]): Set the channel AMA Flags for billing\n" 00338 "purposes. Always returns 0.\n" 00339 }, 00340 00341 { "SetGlobalVar", pbx_builtin_setglobalvar, 00342 "Set global variable to value", 00343 " SetGlobalVar(#n=value): Sets global variable n to value. Global\n" 00344 "variable are available across channels.\n" 00345 }, 00346 00347 { "SetLanguage", pbx_builtin_setlanguage, 00348 "Sets user language", 00349 " SetLanguage(language): Set the channel language to 'language'. This\n" 00350 "information is used for the syntax in generation of numbers, and to choose\n" 00351 "a natural language file when available.\n" 00352 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n" 00353 "requested to be played, if the file 'fr/demo-congrats' exists, then\n" 00354 "it will play that file, and if not will play the normal 'demo-congrats'.\n" 00355 "Always returns 0.\n" 00356 }, 00357 00358 { "SetVar", pbx_builtin_setvar, 00359 "Set variable to value", 00360 " Setvar(#n=value): Sets channel specific variable n to value" 00361 }, 00362 00363 { "StripMSD", pbx_builtin_stripmsd, 00364 "Strip leading digits", 00365 " StripMSD(count): Strips the leading 'count' digits from the channel's\n" 00366 "associated extension. For example, the number 5551212 when stripped with a\n" 00367 "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n" 00368 "will continue processing at the next priority for the *new* extension.\n" 00369 " So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n" 00370 "executed will be priority 4 of 1212. If you switch into an extension which\n" 00371 "has no first step, the PBX will treat it as though the user dialed an\n" 00372 "invalid extension.\n" 00373 }, 00374 00375 { "Suffix", pbx_builtin_suffix, 00376 "Append trailing digits", 00377 " Suffix(digits): Appends the digit string specified by digits to the\n" 00378 "channel's associated extension. For example, the number 555 when suffixed\n" 00379 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n" 00380 "continue processing at the next priority for the *new* extension.\n" 00381 " So, for example, if priority 3 of 555 is Suffix 1212, the next step\n" 00382 "executed will be priority 4 of 5551212. If you switch into an extension\n" 00383 "which has no first step, the PBX will treat it as though the user dialed an\n" 00384 "invalid extension.\n" 00385 }, 00386 00387 { "Wait", pbx_builtin_wait, 00388 "Waits for some time", 00389 " Wait(seconds): Waits for a specified number of seconds, then returns 0.\n" 00390 "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" 00391 }, 00392 00393 { "WaitExten", pbx_builtin_waitexten, 00394 "Waits for some time", 00395 " Wait(seconds): Waits for the user to enter a new extension for the \n" 00396 "specified number of seconds, then returns 0. Seconds can be passed with\n" 00397 "fractions of a second. (eg: 1.5 = 1.5 seconds)\n" 00398 }, 00399 00400 }; 00401 00402 AST_MUTEX_DEFINE_STATIC(applock); /* Lock for the application list */ 00403 static struct ast_context *contexts = NULL; 00404 AST_MUTEX_DEFINE_STATIC(conlock); /* Lock for the ast_context list */ 00405 static struct ast_app *apps = NULL; 00406 00407 AST_MUTEX_DEFINE_STATIC(switchlock); /* Lock for switches */ 00408 struct ast_switch *switches = NULL; 00409 00410 AST_MUTEX_DEFINE_STATIC(hintlock); /* Lock for extension state notifys */ 00411 static int stateid = 1; 00412 struct ast_hint *hints = NULL; 00413 struct ast_state_cb *statecbs = NULL; 00414 00415 int pbx_exec(struct ast_channel *c, /* Channel */ 00416 struct ast_app *app, /* Application */ 00417 void *data, /* Data for execution */ 00418 int newstack) /* Force stack increment */ 00419 { 00420 /* This function is special. It saves the stack so that no matter 00421 how many times it is called, it returns to the same place */ 00422 int res; 00423 00424 char *saved_c_appl; 00425 char *saved_c_data; 00426 00427 int stack = c->stack; 00428 int (*execute)(struct ast_channel *chan, void *data) = app->execute; 00429 00430 if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) { 00431 /* Don't allow us to go over the max number of stacks we 00432 permit saving. */ 00433 ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n"); 00434 return -1; 00435 } 00436 if (newstack && (res = setjmp(c->jmp[++c->stack]))) { 00437 /* Okay, here's where it gets weird. If newstack is non-zero, 00438 then we increase the stack increment, but setjmp is not going 00439 to return until longjmp is called -- when the application 00440 exec'd is finished running. */ 00441 if (res == 1) 00442 res = 0; 00443 if (c->stack != stack + 1) 00444 ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n"); 00445 else if (c->app[c->stack]) 00446 ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n"); 00447 c->stack = stack; 00448 return res; 00449 } else { 00450 if (c->cdr) 00451 ast_cdr_setapp(c->cdr, app->name, data); 00452 00453 /* save channel values */ 00454 saved_c_appl= c->appl; 00455 saved_c_data= c->data; 00456 00457 c->appl = app->name; 00458 c->data = data; 00459 res = execute(c, data); 00460 /* restore channel values */ 00461 c->appl= saved_c_appl; 00462 c->data= saved_c_data; 00463 00464 /* Any application that returns, we longjmp back, just in case. */ 00465 if (c->stack != stack + 1) 00466 ast_log(LOG_WARNING, "Stack is not at expected value\n"); 00467 longjmp(c->jmp[stack+1], res); 00468 /* Never returns */ 00469 } 00470 } 00471 00472 00473 /* Go no deeper than this through includes (not counting loops) */ 00474 #define AST_PBX_MAX_STACK 64 00475 00476 #define HELPER_EXISTS 0 00477 #define HELPER_SPAWN 1 00478 #define HELPER_EXEC 2 00479 #define HELPER_CANMATCH 3 00480 #define HELPER_MATCHMORE 4 00481 00482 struct ast_app *pbx_findapp(char *app) 00483 { 00484 struct ast_app *tmp; 00485 00486 if (ast_mutex_lock(&applock)) { 00487 ast_log(LOG_WARNING, "Unable to obtain application lock\n"); 00488 return NULL; 00489 } 00490 tmp = apps; 00491 while(tmp) { 00492 if (!strcasecmp(tmp->name, app)) 00493 break; 00494 tmp = tmp->next; 00495 } 00496 ast_mutex_unlock(&applock); 00497 return tmp; 00498 } 00499 00500 static struct ast_switch *pbx_findswitch(char *sw) 00501 { 00502 struct ast_switch *asw; 00503 00504 if (ast_mutex_lock(&switchlock)) { 00505 ast_log(LOG_WARNING, "Unable to obtain application lock\n"); 00506 return NULL; 00507 } 00508 asw = switches; 00509 while(asw) { 00510 if (!strcasecmp(asw->name, sw)) 00511 break; 00512 asw = asw->next; 00513 } 00514 ast_mutex_unlock(&switchlock); 00515 return asw; 00516 } 00517 00518 static inline int include_valid(struct ast_include *i) 00519 { 00520 struct tm tm; 00521 time_t t; 00522 00523 if (!i->hastime) 00524 return 1; 00525 time(&t); 00526 localtime_r(&t,&tm); 00527 00528 /* If it's not the right month, return */ 00529 if (!(i->monthmask & (1 << tm.tm_mon))) { 00530 return 0; 00531 } 00532 00533 /* If it's not that time of the month.... */ 00534 /* Warning, tm_mday has range 1..31! */ 00535 if (!(i->daymask & (1 << (tm.tm_mday-1)))) 00536 return 0; 00537 00538 /* If it's not the right day of the week */ 00539 if (!(i->dowmask & (1 << tm.tm_wday))) 00540 return 0; 00541 00542 /* Sanity check the hour just to be safe */ 00543 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) { 00544 ast_log(LOG_WARNING, "Insane time...\n"); 00545 return 0; 00546 } 00547 00548 /* Now the tough part, we calculate if it fits 00549 in the right time based on min/hour */ 00550 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2)))) 00551 return 0; 00552 00553 /* If we got this far, then we're good */ 00554 return 1; 00555 } 00556 00557 static void pbx_destroy(struct ast_pbx *p) 00558 { 00559 free(p); 00560 } 00561 00562 #define EXTENSION_MATCH_CORE(data,pattern,match) {\ 00563 /* All patterns begin with _ */\ 00564 if (pattern[0] != '_') \ 00565 return 0;\ 00566 /* Start optimistic */\ 00567 match=1;\ 00568 pattern++;\ 00569 while(match && *data && *pattern && (*pattern != '/')) {\ 00570 switch(toupper(*pattern)) {\ 00571 case '[': \ 00572 {\ 00573 int i,border=0;\ 00574 char *where;\ 00575 match=0;\ 00576 pattern++;\ 00577 where=strchr(pattern,']');\ 00578 if (where)\ 00579 border=(int)(where-pattern);\ 00580 if (!where || border > strlen(pattern)) {\ 00581 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\ 00582 return match;\ 00583 }\ 00584 for (i=0; i<border; i++) {\ 00585 int res=0;\ 00586 if (i+2<border)\ 00587 if (pattern[i+1]=='-') {\ 00588 if (*data >= pattern[i] && *data <= pattern[i+2]) {\ 00589 res=1;\ 00590 } else {\ 00591 i+=2;\ 00592 continue;\ 00593 }\ 00594 }\ 00595 if (res==1 || *data==pattern[i]) {\ 00596 match = 1;\ 00597 break;\ 00598 }\ 00599 }\ 00600 pattern+=border;\ 00601 break;\ 00602 }\ 00603 case 'N':\ 00604 if ((*data < '2') || (*data > '9'))\ 00605 match=0;\ 00606 break;\ 00607 case 'X':\ 00608 if ((*data < '0') || (*data > '9'))\ 00609 match = 0;\ 00610 break;\ 00611 case 'Z':\ 00612 if ((*data < '1') || (*data > '9'))\ 00613 match = 0;\ 00614 break;\ 00615 case '.':\ 00616 /* Must match */\ 00617 return 1;\ 00618 case ' ':\ 00619 case '-':\ 00620 /* Ignore these characters */\ 00621 data--;\ 00622 break;\ 00623 default:\ 00624 if (*data != *pattern)\ 00625 match =0;\ 00626 }\ 00627 data++;\ 00628 pattern++;\ 00629 }\ 00630 } 00631 00632 int ast_extension_match(char *pattern, char *data) 00633 { 00634 int match; 00635 /* If they're the same return */ 00636 if (!strcmp(pattern, data)) 00637 return 1; 00638 EXTENSION_MATCH_CORE(data,pattern,match); 00639 /* Must be at the end of both */ 00640 if (*data || (*pattern && (*pattern != '/'))) 00641 match = 0; 00642 return match; 00643 } 00644 00645 static int extension_close(char *pattern, char *data, int needmore) 00646 { 00647 int match; 00648 /* If "data" is longer, it can'be a subset of pattern unless 00649 pattern is a pattern match */ 00650 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_')) 00651 return 0; 00652 00653 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) && 00654 (!needmore || (strlen(pattern) > strlen(data)))) { 00655 return 1; 00656 } 00657 EXTENSION_MATCH_CORE(data,pattern,match); 00658 /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */ 00659 if (!needmore || *pattern) { 00660 return match; 00661 } else 00662 return 0; 00663 } 00664 00665 struct ast_context *ast_context_find(char *name) 00666 { 00667 struct ast_context *tmp; 00668 ast_mutex_lock(&conlock); 00669 if (name) { 00670 tmp = contexts; 00671 while(tmp) { 00672 if (!strcasecmp(name, tmp->name)) 00673 break; 00674 tmp = tmp->next; 00675 } 00676 } else 00677 tmp = contexts; 00678 ast_mutex_unlock(&conlock); 00679 return tmp; 00680 } 00681 00682 #define STATUS_NO_CONTEXT 1 00683 #define STATUS_NO_EXTENSION 2 00684 #define STATUS_NO_PRIORITY 3 00685 #define STATUS_SUCCESS 4 00686 00687 static int matchcid(char *cidpattern, char *callerid) 00688 { 00689 char tmp[AST_MAX_EXTENSION]; 00690 int failresult; 00691 char *name, *num; 00692 00693 /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so 00694 failing to get a number should count as a match, otherwise not */ 00695 00696 00697 if (!ast_strlen_zero(cidpattern)) 00698 failresult = 0; 00699 else 00700 failresult = 1; 00701 00702 if (!callerid) 00703 return failresult; 00704 00705 /* Copy original Caller*ID */ 00706 strncpy(tmp, callerid, sizeof(tmp)-1); 00707 /* Parse Number */ 00708 if (ast_callerid_parse(tmp, &name, &num)) 00709 return failresult; 00710 if (!num) 00711 return failresult; 00712 ast_shrink_phone_number(num); 00713 return ast_extension_match(cidpattern, num); 00714 } 00715 00716 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data) 00717 { 00718 int x, res; 00719 struct ast_context *tmp; 00720 struct ast_exten *e, *eroot; 00721 struct ast_include *i; 00722 struct ast_sw *sw; 00723 struct ast_switch *asw; 00724 00725 /* Initialize status if appropriate */ 00726 if (!*stacklen) { 00727 *status = STATUS_NO_CONTEXT; 00728 *swo = NULL; 00729 *data = NULL; 00730 } 00731 /* Check for stack overflow */ 00732 if (*stacklen >= AST_PBX_MAX_STACK) { 00733 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n"); 00734 return NULL; 00735 } 00736 /* Check first to see if we've already been checked */ 00737 for (x=0;x<*stacklen;x++) { 00738 if (!strcasecmp(incstack[x], context)) 00739 return NULL; 00740 } 00741 tmp = contexts; 00742 while(tmp) { 00743 /* Match context */ 00744 if (!strcmp(tmp->name, context)) { 00745 if (*status < STATUS_NO_EXTENSION) 00746 *status = STATUS_NO_EXTENSION; 00747 eroot = tmp->root; 00748 while(eroot) { 00749 /* Match extension */ 00750 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) || 00751 ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) || 00752 ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) && 00753 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) { 00754 e = eroot; 00755 if (*status < STATUS_NO_PRIORITY) 00756 *status = STATUS_NO_PRIORITY; 00757 while(e) { 00758 /* Match priority */ 00759 if (e->priority == priority) { 00760 *status = STATUS_SUCCESS; 00761 return e; 00762 } 00763 e = e->peer; 00764 } 00765 } 00766 eroot = eroot->next; 00767 } 00768 /* Check alternative switches */ 00769 sw = tmp->alts; 00770 while(sw) { 00771 if ((asw = pbx_findswitch(sw->name))) { 00772 if (action == HELPER_CANMATCH) 00773 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0; 00774 else if (action == HELPER_MATCHMORE) 00775 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0; 00776 else 00777 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0; 00778 if (res) { 00779 /* Got a match */ 00780 *swo = asw; 00781 *data = sw->data; 00782 return NULL; 00783 } 00784 } else { 00785 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name); 00786 } 00787 sw = sw->next; 00788 } 00789 /* Setup the stack */ 00790 incstack[*stacklen] = tmp->name; 00791 (*stacklen)++; 00792 /* Now try any includes we have in this context */ 00793 i = tmp->includes; 00794 while(i) { 00795 if (include_valid(i)) { 00796 if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data))) 00797 return e; 00798 if (*swo) 00799 return NULL; 00800 } 00801 i = i->next; 00802 } 00803 } 00804 tmp = tmp->next; 00805 } 00806 return NULL; 00807 } 00808 00809 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen) 00810 { 00811 char *first,*second; 00812 char tmpvar[80] = ""; 00813 time_t thistime; 00814 struct tm brokentime; 00815 int offset,offset2; 00816 struct ast_var_t *variables; 00817 char *name, *num; /* for callerid name + num variables */ 00818 struct varshead *headp=NULL; 00819 00820 if (c) 00821 headp=&c->varshead; 00822 *ret=NULL; 00823 /* Now we have the variable name on cp3 */ 00824 if (!strncasecmp(var,"LEN(",4)) { 00825 int len=strlen(var); 00826 int len_len=4; 00827 if (strrchr(var,')')) { 00828 char cp3[80]; 00829 strncpy(cp3, var, sizeof(cp3) - 1); 00830 cp3[len-len_len-1]='\0'; 00831 sprintf(workspace,"%d",(int)strlen(cp3)); 00832 *ret = workspace; 00833 } else { 00834 /* length is zero */ 00835 *ret = "0"; 00836 } 00837 } else if ((first=strchr(var,':'))) { 00838 strncpy(tmpvar, var, sizeof(tmpvar) - 1); 00839 first = strchr(tmpvar, ':'); 00840 if (!first) 00841 first = tmpvar + strlen(tmpvar); 00842 *first='\0'; 00843 pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1); 00844 if (!(*ret)) return; 00845 offset=atoi(first+1); 00846 if ((second=strchr(first+1,':'))) { 00847 *second='\0'; 00848 offset2=atoi(second+1); 00849 } else 00850 offset2=strlen(*ret)-offset; 00851 if (abs(offset)>strlen(*ret)) { 00852 if (offset>=0) 00853 offset=strlen(*ret); 00854 else 00855 offset=-strlen(*ret); 00856 } 00857 if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) { 00858 if (offset>=0) 00859 offset2=strlen(*ret)-offset; 00860 else 00861 offset2=strlen(*ret)+offset; 00862 } 00863 if (offset>=0) 00864 *ret+=offset; 00865 else 00866 *ret+=strlen(*ret)+offset; 00867 (*ret)[offset2] = '\0'; 00868 } else if (c && !strcmp(var, "CALLERIDNUM")) { 00869 if (c->callerid) 00870 strncpy(workspace, c->callerid, workspacelen - 1); 00871 ast_callerid_parse(workspace, &name, &num); 00872 if (num) { 00873 ast_shrink_phone_number(num); 00874 *ret = num; 00875 } else 00876 *ret = workspace; 00877 } else if (c && !strcmp(var, "CALLERIDNAME")) { 00878 if (c->callerid) 00879 strncpy(workspace, c->callerid, workspacelen - 1); 00880 ast_callerid_parse(workspace, &name, &num); 00881 if (name) 00882 *ret = name; 00883 else 00884 *ret = workspace; 00885 } else if (c && !strcmp(var, "CALLERID")) { 00886 if (c->callerid) { 00887 strncpy(workspace, c->callerid, workspacelen - 1); 00888 *ret = workspace; 00889 } else 00890 *ret = NULL; 00891 } else if (c && !strcmp(var, "DNID")) { 00892 if (c->dnid) { 00893 strncpy(workspace, c->dnid, workspacelen - 1); 00894 *ret = workspace; 00895 } else 00896 *ret = NULL; 00897 } else if (c && !strcmp(var, "HINT")) { 00898 if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten)) 00899 *ret = NULL; 00900 else 00901 *ret = workspace; 00902 } else if (c && !strcmp(var, "EXTEN")) { 00903 strncpy(workspace, c->exten, workspacelen - 1); 00904 *ret = workspace; 00905 } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) && 00906 /* XXX Remove me eventually */ 00907 (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) { 00908 if (offset < 0) 00909 offset=0; 00910 if (offset > strlen(c->exten)) 00911 offset = strlen(c->exten); 00912 strncpy(workspace, c->exten + offset, workspacelen - 1); 00913 *ret = workspace; 00914 ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n"); 00915 } else if (c && !strcmp(var, "RDNIS")) { 00916 if (c->rdnis) { 00917 strncpy(workspace, c->rdnis, workspacelen - 1); 00918 *ret = workspace; 00919 } else 00920 *ret = NULL; 00921 } else if (c && !strcmp(var, "CONTEXT")) { 00922 strncpy(workspace, c->context, workspacelen - 1); 00923 *ret = workspace; 00924 } else if (c && !strcmp(var, "PRIORITY")) { 00925 snprintf(workspace, workspacelen, "%d", c->priority); 00926 *ret = workspace; 00927 } else if (c && !strcmp(var, "CHANNEL")) { 00928 strncpy(workspace, c->name, workspacelen - 1); 00929 *ret = workspace; 00930 } else if (c && !strcmp(var, "EPOCH")) { 00931 snprintf(workspace, workspacelen, "%u",(int)time(NULL)); 00932 *ret = workspace; 00933 } else if (c && !strcmp(var, "DATETIME")) { 00934 thistime=time(NULL); 00935 localtime_r(&thistime, &brokentime); 00936 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d", 00937 brokentime.tm_mday, 00938 brokentime.tm_mon+1, 00939 brokentime.tm_year+1900, 00940 brokentime.tm_hour, 00941 brokentime.tm_min, 00942 brokentime.tm_sec 00943 ); 00944 *ret = workspace; 00945 } else if (c && !strcmp(var, "TIMESTAMP")) { 00946 thistime=time(NULL); 00947 localtime_r(&thistime, &brokentime); 00948 /* 20031130-150612 */ 00949 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d", 00950 brokentime.tm_year+1900, 00951 brokentime.tm_mon+1, 00952 brokentime.tm_mday, 00953 brokentime.tm_hour, 00954 brokentime.tm_min, 00955 brokentime.tm_sec 00956 ); 00957 *ret = workspace; 00958 } else if (c && !strcmp(var, "UNIQUEID")) { 00959 snprintf(workspace, workspacelen, "%s", c->uniqueid); 00960 *ret = workspace; 00961 } else if (c && !strcmp(var, "HANGUPCAUSE")) { 00962 snprintf(workspace, workspacelen, "%i", c->hangupcause); 00963 *ret = workspace; 00964 } else if (c && !strcmp(var, "ACCOUNTCODE")) { 00965 strncpy(workspace, c->accountcode, workspacelen - 1); 00966 *ret = workspace; 00967 } else if (c && !strcmp(var, "LANGUAGE")) { 00968 strncpy(workspace, c->language, workspacelen - 1); 00969 *ret = workspace; 00970 } else { 00971 if (c) { 00972 AST_LIST_TRAVERSE(headp,variables,entries) { 00973 #if 0 00974 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables)); 00975 #endif 00976 if (strcasecmp(ast_var_name(variables),var)==0) { 00977 *ret=ast_var_value(variables); 00978 if (*ret) { 00979 strncpy(workspace, *ret, workspacelen - 1); 00980 *ret = workspace; 00981 } 00982 break; 00983 } 00984 } 00985 } 00986 if (!(*ret)) { 00987 /* Try globals */ 00988 AST_LIST_TRAVERSE(&globals,variables,entries) { 00989 #if 0 00990 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables)); 00991 #endif 00992 if (strcasecmp(ast_var_name(variables),var)==0) { 00993 *ret=ast_var_value(variables); 00994 if (*ret) { 00995 strncpy(workspace, *ret, workspacelen - 1); 00996 *ret = workspace; 00997 } 00998 } 00999 } 01000 } 01001 if (!(*ret)) { 01002 int len=strlen(var); 01003 int len_env=strlen("ENV("); 01004 if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) { 01005 char cp3[80] = ""; 01006 strncpy(cp3, var, sizeof(cp3) - 1); 01007 cp3[len-1]='\0'; 01008 *ret=getenv(cp3+len_env); 01009 if (*ret) { 01010 strncpy(workspace, *ret, workspacelen - 1); 01011 *ret = workspace; 01012 } 01013 } 01014 } 01015 } 01016 } 01017 01018 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count) 01019 { 01020 char *cp4; 01021 const char *tmp, *whereweare; 01022 int length; 01023 char workspace[4096]; 01024 char ltmp[4096], var[4096]; 01025 char *nextvar, *nextexp; 01026 char *vars, *vare; 01027 int pos, brackets, needsub, len; 01028 01029 /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be 01030 zero-filled */ 01031 whereweare=tmp=cp1; 01032 while(!ast_strlen_zero(whereweare) && count) { 01033 /* Assume we're copying the whole remaining string */ 01034 pos = strlen(whereweare); 01035 01036 /* Look for a variable */ 01037 nextvar = strstr(whereweare, "${"); 01038 01039 /* Look for an expression */ 01040 nextexp = strstr(whereweare, "$["); 01041 01042 /* Pick the first one only */ 01043 if (nextvar && nextexp) { 01044 if (nextvar < nextexp) 01045 nextexp = NULL; 01046 else 01047 nextvar = NULL; 01048 } 01049 01050 /* If there is one, we only go that far */ 01051 if (nextvar) 01052 pos = nextvar - whereweare; 01053 else if (nextexp) 01054 pos = nextexp - whereweare; 01055 01056 /* Can't copy more than 'count' bytes */ 01057 if (pos > count) 01058 pos = count; 01059 01060 /* Copy that many bytes */ 01061 memcpy(cp2, whereweare, pos); 01062 01063 count -= pos; 01064 cp2 += pos; 01065 whereweare += pos; 01066 01067 if (nextvar) { 01068 /* We have a variable. Find the start and end, and determine 01069 if we are going to have to recursively call ourselves on the 01070 contents */ 01071 vars = vare = nextvar + 2; 01072 brackets = 1; 01073 needsub = 0; 01074 01075 /* Find the end of it */ 01076 while(brackets && *vare) { 01077 if ((vare[0] == '$') && (vare[1] == '{')) { 01078 needsub++; 01079 brackets++; 01080 } else if (vare[0] == '}') { 01081 brackets--; 01082 } else if ((vare[0] == '$') && (vare[1] == '[')) 01083 needsub++; 01084 vare++; 01085 } 01086 if (brackets) 01087 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n"); 01088 len = vare - vars - 1; 01089 01090 /* Skip totally over variable name */ 01091 whereweare += ( len + 3); 01092 01093 /* Store variable name (and truncate) */ 01094 memset(var, 0, sizeof(var)); 01095 strncpy(var, vars, sizeof(var) - 1); 01096 var[len] = '\0'; 01097 01098 /* Substitute if necessary */ 01099 if (needsub) { 01100 memset(ltmp, 0, sizeof(ltmp)); 01101 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1); 01102 vars = ltmp; 01103 } else { 01104 vars = var; 01105 } 01106 01107 /* Retrieve variable value */ 01108 workspace[0] = '\0'; 01109 pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace)); 01110 if (cp4) { 01111 length = strlen(cp4); 01112 if (length > count) 01113 length = count; 01114 memcpy(cp2, cp4, length); 01115 count -= length; 01116 cp2 += length; 01117 } 01118 01119 } else if (nextexp) { 01120 /* We have an expression. Find the start and end, and determine 01121 if we are going to have to recursively call ourselves on the 01122 contents */ 01123 vars = vare = nextexp + 2; 01124 brackets = 1; 01125 needsub = 0; 01126 01127 /* Find the end of it */ 01128 while(brackets && *vare) { 01129 if ((vare[0] == '$') && (vare[1] == '[')) { 01130 needsub++; 01131 brackets++; 01132 vare++; 01133 } else if (vare[0] == '[') { 01134 brackets++; 01135 } else if (vare[0] == ']') { 01136 brackets--; 01137 } else if ((vare[0] == '$') && (vare[1] == '{')) { 01138 needsub++; 01139 vare++; 01140 } 01141 vare++; 01142 } 01143 if (brackets) 01144 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n"); 01145 len = vare - vars - 1; 01146 01147 /* Skip totally over variable name */ 01148 whereweare += ( len + 3); 01149 01150 /* Store variable name (and truncate) */ 01151 memset(var, 0, sizeof(var)); 01152 strncpy(var, vars, sizeof(var) - 1); 01153 var[len] = '\0'; 01154 01155 /* Substitute if necessary */ 01156 if (needsub) { 01157 memset(ltmp, 0, sizeof(ltmp)); 01158 pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1); 01159 vars = ltmp; 01160 } else { 01161 vars = var; 01162 } 01163 01164 /* Evaluate expression */ 01165 cp4 = ast_expr(vars); 01166 01167 ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4); 01168 01169 if (cp4) { 01170 length = strlen(cp4); 01171 if (length > count) 01172 length = count; 01173 memcpy(cp2, cp4, length); 01174 count -= length; 01175 cp2 += length; 01176 free(cp4); 01177 } 01178 01179 } else 01180 break; 01181 } 01182 } 01183 01184 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) { 01185 01186 memset(passdata, 0, datalen); 01187 01188 /* No variables or expressions in e->data, so why scan it? */ 01189 if (!strstr(e->data,"${") && !strstr(e->data,"$[")) { 01190 strncpy(passdata, e->data, datalen - 1); 01191 passdata[datalen-1] = '\0'; 01192 return; 01193 } 01194 01195 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1); 01196 } 01197 01198 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action) 01199 { 01200 struct ast_exten *e; 01201 struct ast_app *app; 01202 struct ast_switch *sw; 01203 char *data; 01204 int newstack = 0; 01205 int res; 01206 int status = 0; 01207 char *incstack[AST_PBX_MAX_STACK]; 01208 char passdata[EXT_DATA_SIZE]; 01209 int stacklen = 0; 01210 char tmp[80]; 01211 char tmp2[80]; 01212 char tmp3[EXT_DATA_SIZE]; 01213 01214 if (ast_mutex_lock(&conlock)) { 01215 ast_log(LOG_WARNING, "Unable to obtain lock\n"); 01216 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE)) 01217 return 0; 01218 else 01219 return -1; 01220 } 01221 e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data); 01222 if (e) { 01223 switch(action) { 01224 case HELPER_CANMATCH: 01225 ast_mutex_unlock(&conlock); 01226 return -1; 01227 case HELPER_EXISTS: 01228 ast_mutex_unlock(&conlock); 01229 return -1; 01230 case HELPER_MATCHMORE: 01231 ast_mutex_unlock(&conlock); 01232 return -1; 01233 case HELPER_SPAWN: 01234 newstack++; 01235 /* Fall through */ 01236 case HELPER_EXEC: 01237 app = pbx_findapp(e->app); 01238 ast_mutex_unlock(&conlock); 01239 if (app) { 01240 if (c->context != context) 01241 strncpy(c->context, context, sizeof(c->context)-1); 01242 if (c->exten != exten) 01243 strncpy(c->exten, exten, sizeof(c->exten)-1); 01244 c->priority = priority; 01245 pbx_substitute_variables(passdata, sizeof(passdata), c, e); 01246 if (option_debug) 01247 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name); 01248 else if (option_verbose > 2) 01249 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 01250 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)), 01251 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)), 01252 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)), 01253 (newstack ? "in new stack" : "in same stack")); 01254 res = pbx_exec(c, app, passdata, newstack); 01255 return res; 01256 } else { 01257 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority); 01258 return -1; 01259 } 01260 default: 01261 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1; 01262 } 01263 } else if (sw) { 01264 switch(action) { 01265 case HELPER_CANMATCH: 01266 ast_mutex_unlock(&conlock); 01267 return -1; 01268 case HELPER_EXISTS: 01269 ast_mutex_unlock(&conlock); 01270 return -1; 01271 case HELPER_MATCHMORE: 01272 ast_mutex_unlock(&conlock); 01273 return -1; 01274 case HELPER_SPAWN: 01275 newstack++; 01276 /* Fall through */ 01277 case HELPER_EXEC: 01278 ast_mutex_unlock(&conlock); 01279 if (sw->exec) 01280 res = sw->exec(c, context, exten, priority, callerid, newstack, data); 01281 else { 01282 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name); 01283 res = -1; 01284 } 01285 return res; 01286 default: 01287 ast_log(LOG_WARNING, "Huh (%d)?\n", action); 01288 return -1; 01289 } 01290 } else { 01291 ast_mutex_unlock(&conlock); 01292 switch(status) { 01293 case STATUS_NO_CONTEXT: 01294 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE)) 01295 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context); 01296 break; 01297 case STATUS_NO_EXTENSION: 01298 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE)) 01299 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context); 01300 break; 01301 case STATUS_NO_PRIORITY: 01302 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE)) 01303 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context); 01304 break; 01305 default: 01306 ast_log(LOG_DEBUG, "Shouldn't happen!\n"); 01307 } 01308 01309 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE)) 01310 return -1; 01311 else 01312 return 0; 01313 } 01314 01315 } 01316 01317 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten) 01318 { 01319 struct ast_exten *e; 01320 struct ast_switch *sw; 01321 char *data; 01322 int status = 0; 01323 char *incstack[AST_PBX_MAX_STACK]; 01324 int stacklen = 0; 01325 01326 if (ast_mutex_lock(&conlock)) { 01327 ast_log(LOG_WARNING, "Unable to obtain lock\n"); 01328 return NULL; 01329 } 01330 e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data); 01331 ast_mutex_unlock(&conlock); 01332 return e; 01333 } 01334 01335 static int ast_extension_state2(struct ast_exten *e) 01336 { 01337 char hint[AST_MAX_EXTENSION] = ""; 01338 char *cur, *rest; 01339 int res = -1; 01340 int allunavailable = 1, allbusy = 1, allfree = 1; 01341 int busy = 0; 01342 01343 strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1); 01344 01345 cur = hint; 01346 do { 01347 rest = strchr(cur, '&'); 01348 if (rest) { 01349 *rest = 0; 01350 rest++; 01351 } 01352 01353 res = ast_device_state(cur); 01354 switch (res) { 01355 case AST_DEVICE_NOT_INUSE: 01356 allunavailable = 0; 01357 allbusy = 0; 01358 break; 01359 case AST_DEVICE_INUSE: 01360 return AST_EXTENSION_INUSE; 01361 case AST_DEVICE_BUSY: 01362 allunavailable = 0; 01363 allfree = 0; 01364 busy = 1; 01365 break; 01366 case AST_DEVICE_UNAVAILABLE: 01367 case AST_DEVICE_INVALID: 01368 allbusy = 0; 01369 allfree = 0; 01370 break; 01371 default: 01372 allunavailable = 0; 01373 allbusy = 0; 01374 allfree = 0; 01375 } 01376 cur = rest; 01377 } while (cur); 01378 01379 if (allfree) 01380 return AST_EXTENSION_NOT_INUSE; 01381 if (allbusy) 01382 return AST_EXTENSION_BUSY; 01383 if (allunavailable) 01384 return AST_EXTENSION_UNAVAILABLE; 01385 if (busy) 01386 return AST_EXTENSION_INUSE; 01387 01388 return AST_EXTENSION_NOT_INUSE; 01389 } 01390 01391 01392 int ast_extension_state(struct ast_channel *c, char *context, char *exten) 01393 { 01394 struct ast_exten *e; 01395 01396 e = ast_hint_extension(c, context, exten); 01397 if (!e) 01398 return -1; 01399 01400 return ast_extension_state2(e); 01401 } 01402 01403 int ast_device_state_changed(const char *fmt, ...) 01404 { 01405 struct ast_hint *list; 01406 struct ast_state_cb *cblist; 01407 char hint[AST_MAX_EXTENSION] = ""; 01408 char device[AST_MAX_EXTENSION]; 01409 char *cur, *rest; 01410 int state; 01411 01412 va_list ap; 01413 01414 va_start(ap, fmt); 01415 vsnprintf(device, sizeof(device), fmt, ap); 01416 va_end(ap); 01417 01418 rest = strchr(device, '-'); 01419 if (rest) { 01420 *rest = 0; 01421 } 01422 01423 ast_mutex_lock(&hintlock); 01424 01425 list = hints; 01426 01427 while (list) { 01428 01429 strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1); 01430 cur = hint; 01431 do { 01432 rest = strchr(cur, '&'); 01433 if (rest) { 01434 *rest = 0; 01435 rest++; 01436 } 01437 01438 if (!strcmp(cur, device)) { 01439 /* Found extension execute callbacks */ 01440 state = ast_extension_state2(list->exten); 01441 if ((state != -1) && (state != list->laststate)) { 01442 /* For general callbacks */ 01443 cblist = statecbs; 01444 while (cblist) { 01445 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data); 01446 cblist = cblist->next; 01447 } 01448 01449 /* For extension callbacks */ 01450 cblist = list->callbacks; 01451 while (cblist) { 01452 cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data); 01453 cblist = cblist->next; 01454 } 01455 01456 list->laststate = state; 01457 } 01458 break; 01459 } 01460 cur = rest; 01461 } while (cur); 01462 list = list->next; 01463 } 01464 ast_mutex_unlock(&hintlock); 01465 return 1; 01466 } 01467 01468 int ast_extension_state_add(char *context, char *exten, 01469 ast_state_cb_type callback, void *data) 01470 { 01471 struct ast_hint *list; 01472 struct ast_state_cb *cblist; 01473 struct ast_exten *e; 01474 01475 /* No context and extension add callback to statecbs list */ 01476 if (!context && !exten) { 01477 ast_mutex_lock(&hintlock); 01478 01479 cblist = statecbs; 01480 while (cblist) { 01481 if (cblist->callback == callback) { 01482 cblist->data = data; 01483 ast_mutex_unlock(&hintlock); 01484 } 01485 cblist = cblist->next; 01486 } 01487 01488 /* Now inserts the callback */ 01489 cblist = malloc(sizeof(struct ast_state_cb)); 01490 if (!cblist) { 01491 ast_mutex_unlock(&hintlock); 01492 return -1; 01493 } 01494 memset(cblist, 0, sizeof(struct ast_state_cb)); 01495 cblist->id = 0; 01496 cblist->callback = callback; 01497 cblist->data = data; 01498 01499 cblist->next = statecbs; 01500 statecbs = cblist; 01501 01502 ast_mutex_unlock(&hintlock); 01503 return 0; 01504 } 01505 01506 if (!context || !exten) 01507 return -1; 01508 01509 /* This callback type is for only one hint */ 01510 e = ast_hint_extension(NULL, context, exten); 01511 if (!e) { 01512 return -1; 01513 } 01514 01515 ast_mutex_lock(&hintlock); 01516 list = hints; 01517 01518 while (list) { 01519 if (list->exten == e) 01520 break; 01521 list = list->next; 01522 } 01523 01524 if (!list) { 01525 ast_mutex_unlock(&hintlock); 01526 return -1; 01527 } 01528 01529 /* Now inserts the callback */ 01530 cblist = malloc(sizeof(struct ast_state_cb)); 01531 if (!cblist) { 01532 ast_mutex_unlock(&hintlock); 01533 return -1; 01534 } 01535 memset(cblist, 0, sizeof(struct ast_state_cb)); 01536 cblist->id = stateid++; 01537 cblist->callback = callback; 01538 cblist->data = data; 01539 01540 cblist->next = list->callbacks; 01541 list->callbacks = cblist; 01542 01543 ast_mutex_unlock(&hintlock); 01544 return cblist->id; 01545 } 01546 01547 int ast_extension_state_del(int id, ast_state_cb_type callback) 01548 { 01549 struct ast_hint *list; 01550 struct ast_state_cb *cblist, *cbprev; 01551 01552 if (!id && !callback) 01553 return -1; 01554 01555 ast_mutex_lock(&hintlock); 01556 01557 /* id is zero is a callback without extension */ 01558 if (!id) { 01559 cbprev = NULL; 01560 cblist = statecbs; 01561 while (cblist) { 01562 if (cblist->callback == callback) { 01563 if (!cbprev) 01564 statecbs = cblist->next; 01565 else 01566 cbprev->next = cblist->next; 01567 01568 free(cblist); 01569 01570 ast_mutex_unlock(&hintlock); 01571 return 0; 01572 } 01573 cbprev = cblist; 01574 cblist = cblist->next; 01575 } 01576 01577 ast_mutex_lock(&hintlock); 01578 return -1; 01579 } 01580 01581 /* id greater than zero is a callback with extension */ 01582 list = hints; 01583 while (list) { 01584 cblist = list->callbacks; 01585 cbprev = NULL; 01586 while (cblist) { 01587 if (cblist->id==id) { 01588 if (!cbprev) 01589 list->callbacks = cblist->next; 01590 else 01591 cbprev->next = cblist->next; 01592 01593 free(cblist); 01594 01595 ast_mutex_unlock(&hintlock); 01596 return 0; 01597 } 01598 cbprev = cblist; 01599 cblist = cblist->next; 01600 } 01601 list = list->next; 01602 } 01603 01604 ast_mutex_unlock(&hintlock); 01605 return -1; 01606 } 01607 01608 static int ast_add_hint(struct ast_exten *e) 01609 { 01610 struct ast_hint *list; 01611 01612 if (!e) 01613 return -1; 01614 01615 ast_mutex_lock(&hintlock); 01616 list = hints; 01617 01618 /* Search if hint exists, do nothing */ 01619 while (list) { 01620 if (list->exten == e) { 01621 ast_mutex_unlock(&hintlock); 01622 return -1; 01623 } 01624 list = list->next; 01625 } 01626 01627 list = malloc(sizeof(struct ast_hint)); 01628 if (!list) { 01629 ast_mutex_unlock(&hintlock); 01630 return -1; 01631 } 01632 /* Initialize and insert new item */ 01633 memset(list, 0, sizeof(struct ast_hint)); 01634 list->exten = e; 01635 list->laststate = ast_extension_state2(e); 01636 list->next = hints; 01637 hints = list; 01638 01639 ast_mutex_unlock(&hintlock); 01640 return 0; 01641 } 01642 01643 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne) 01644 { 01645 struct ast_hint *list; 01646 01647 ast_mutex_lock(&hintlock); 01648 list = hints; 01649 01650 while(list) { 01651 if (list->exten == oe) { 01652 list->exten = ne; 01653 ast_mutex_unlock(&hintlock); 01654 return 0; 01655 } 01656 list = list->next; 01657 } 01658 ast_mutex_unlock(&hintlock); 01659 01660 return -1; 01661 } 01662 01663 static int ast_remove_hint(struct ast_exten *e) 01664 { 01665 /* Cleanup the Notifys if hint is removed */ 01666 struct ast_hint *list, *prev = NULL; 01667 struct ast_state_cb *cblist, *cbprev; 01668 01669 if (!e) 01670 return -1; 01671 01672 ast_mutex_lock(&hintlock); 01673 01674 list = hints; 01675 while(list) { 01676 if (list->exten==e) { 01677 cbprev = NULL; 01678 cblist = list->callbacks; 01679 while (cblist) { 01680 /* Notify with -1 and remove all callbacks */ 01681 cbprev = cblist; 01682 cblist = cblist->next; 01683 cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data); 01684 free(cbprev); 01685 } 01686 list->callbacks = NULL; 01687 01688 if (!prev) 01689 hints = list->next; 01690 else 01691 prev->next = list->next; 01692 free(list); 01693 01694 ast_mutex_unlock(&hintlock); 01695 return 0; 01696 } else { 01697 prev = list; 01698 list = list->next; 01699 } 01700 } 01701 01702 ast_mutex_unlock(&hintlock); 01703 return -1; 01704 } 01705 01706 01707 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, char *context, char *exten) 01708 { 01709 struct ast_exten *e; 01710 e = ast_hint_extension(c, context, exten); 01711 if (e) { 01712 strncpy(hint, ast_get_extension_app(e), hintsize - 1); 01713 return -1; 01714 } 01715 return 0; 01716 } 01717 01718 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 01719 { 01720 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS); 01721 } 01722 01723 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 01724 { 01725 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH); 01726 } 01727 01728 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 01729 { 01730 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE); 01731 } 01732 01733 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 01734 { 01735 return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN); 01736 } 01737 01738 int ast_pbx_run(struct ast_channel *c) 01739 { 01740 int firstpass = 1; 01741 char digit; 01742 char exten[256]; 01743 int pos; 01744 int waittime; 01745 int res=0; 01746 01747 /* A little initial setup here */ 01748 if (c->pbx) 01749 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name); 01750 c->pbx = malloc(sizeof(struct ast_pbx)); 01751 if (!c->pbx) { 01752 ast_log(LOG_ERROR, "Out of memory\n"); 01753 return -1; 01754 } 01755 if (c->amaflags) { 01756 if (c->cdr) { 01757 ast_log(LOG_WARNING, "%s already has a call record??\n", c->name); 01758 } else { 01759 c->cdr = ast_cdr_alloc(); 01760 if (!c->cdr) { 01761 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n"); 01762 free(c->pbx); 01763 return -1; 01764 } 01765 ast_cdr_init(c->cdr, c); 01766 } 01767 } 01768 memset(c->pbx, 0, sizeof(struct ast_pbx)); 01769 /* Set reasonable defaults */ 01770 c->pbx->rtimeout = 10; 01771 c->pbx->dtimeout = 5; 01772 01773 /* Start by trying whatever the channel is set to */ 01774 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) { 01775 /* JK02: If not successfull fall back to 's' */ 01776 strncpy(c->exten, "s", sizeof(c->exten)-1); 01777 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) { 01778 /* JK02: And finally back to default if everything else failed */ 01779 strncpy(c->context, "default", sizeof(c->context)-1); 01780 } 01781 c->priority = 1; 01782 } 01783 if (c->cdr) 01784 ast_cdr_start(c->cdr); 01785 for(;;) { 01786 pos = 0; 01787 digit = 0; 01788 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) { 01789 memset(exten, 0, sizeof(exten)); 01790 manager_event(EVENT_FLAG_CALL, "Newexten", 01791 "Channel: %s\r\n" 01792 "Context: %s\r\n" 01793 "Extension: %s\r\n" 01794 "Priority: %d\r\n" 01795 "Uniqueid: %s\r\n", 01796 c->name, c->context, c->exten, c->priority, c->uniqueid); 01797 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) { 01798 /* Something bad happened, or a hangup has been requested. */ 01799 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) || 01800 (res == '*') || (res == '#')) { 01801 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res); 01802 memset(exten, 0, sizeof(exten)); 01803 pos = 0; 01804 exten[pos++] = digit = res; 01805 break; 01806 } 01807 switch(res) { 01808 case AST_PBX_KEEPALIVE: 01809 if (option_debug) 01810 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name); 01811 else if (option_verbose > 1) 01812 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name); 01813 goto out; 01814 break; 01815 default: 01816 if (option_debug) 01817 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 01818 else if (option_verbose > 1) 01819 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 01820 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) { 01821 c->_softhangup =0; 01822 break; 01823 } 01824 /* atimeout */ 01825 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) { 01826 break; 01827 } 01828 01829 if (c->cdr) { 01830 ast_cdr_update(c); 01831 } 01832 goto out; 01833 } 01834 } 01835 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) { 01836 strncpy(c->exten,"T",sizeof(c->exten) - 1); 01837 /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */ 01838 c->whentohangup = 0; 01839 c->priority = 0; 01840 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT; 01841 } else if (c->_softhangup) { 01842 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n", 01843 c->exten, c->priority); 01844 goto out; 01845 } 01846 firstpass = 0; 01847 c->priority++; 01848 } 01849 if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) { 01850 /* It's not a valid extension anymore */ 01851 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) { 01852 if (option_verbose > 2) 01853 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name); 01854 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten); 01855 strncpy(c->exten, "i", sizeof(c->exten)-1); 01856 c->priority = 1; 01857 } else { 01858 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n", 01859 c->name, c->exten, c->context); 01860 goto out; 01861 } 01862 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) { 01863 /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */ 01864 c->_softhangup = 0; 01865 } else { 01866 /* Done, wait for an extension */ 01867 if (digit) 01868 waittime = c->pbx->dtimeout; 01869 else 01870 waittime = c->pbx->rtimeout; 01871 while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) { 01872 /* As long as we're willing to wait, and as long as it's not defined, 01873 keep reading digits until we can't possibly get a right answer anymore. */ 01874 digit = ast_waitfordigit(c, waittime * 1000); 01875 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) { 01876 c->_softhangup = 0; 01877 } else { 01878 if (!digit) 01879 /* No entry */ 01880 break; 01881 if (digit < 0) 01882 /* Error, maybe a hangup */ 01883 goto out; 01884 exten[pos++] = digit; 01885 waittime = c->pbx->dtimeout; 01886 } 01887 } 01888 if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) { 01889 /* Prepare the next cycle */ 01890 strncpy(c->exten, exten, sizeof(c->exten)-1); 01891 c->priority = 1; 01892 } else { 01893 /* No such extension */ 01894 if (!ast_strlen_zero(exten)) { 01895 /* An invalid extension */ 01896 if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) { 01897 if (option_verbose > 2) 01898 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name); 01899 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten); 01900 strncpy(c->exten, "i", sizeof(c->exten)-1); 01901 c->priority = 1; 01902 } else { 01903 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context); 01904 goto out; 01905 } 01906 } else { 01907 /* A simple timeout */ 01908 if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) { 01909 if (option_verbose > 2) 01910 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name); 01911 strncpy(c->exten, "t", sizeof(c->exten)-1); 01912 c->priority = 1; 01913 } else { 01914 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context); 01915 goto out; 01916 } 01917 } 01918 } 01919 if (c->cdr) { 01920 if (option_verbose > 2) 01921 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name); 01922 ast_cdr_update(c); 01923 } 01924 } 01925 } 01926 if (firstpass) 01927 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name); 01928 out: 01929 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) { 01930 c->exten[0] = 'h'; 01931 c->exten[1] = '\0'; 01932 c->priority = 1; 01933 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) { 01934 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) { 01935 /* Something bad happened, or a hangup has been requested. */ 01936 if (option_debug) 01937 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 01938 else if (option_verbose > 1) 01939 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); 01940 break; 01941 } 01942 c->priority++; 01943 } 01944 } 01945 01946 pbx_destroy(c->pbx); 01947 c->pbx = NULL; 01948 if (res != AST_PBX_KEEPALIVE) 01949 ast_hangup(c); 01950 return 0; 01951 } 01952 01953 static void *pbx_thread(void *data) 01954 { 01955 /* Oh joyeous kernel, we're a new thread, with nothing to do but 01956 answer this channel and get it going. The setjmp stuff is fairly 01957 confusing, but necessary to get smooth transitions between 01958 the execution of different applications (without the use of 01959 additional threads) */ 01960 struct ast_channel *c = data; 01961 ast_pbx_run(c); 01962 pthread_exit(NULL); 01963 return NULL; 01964 } 01965 01966 int ast_pbx_start(struct ast_channel *c) 01967 { 01968 pthread_t t; 01969 pthread_attr_t attr; 01970 if (!c) { 01971 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n"); 01972 return -1; 01973 } 01974 01975 /* Start a new thread, and get something handling this channel. */ 01976 pthread_attr_init(&attr); 01977 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01978 if (pthread_create(&t, &attr, pbx_thread, c)) { 01979 ast_log(LOG_WARNING, "Failed to create new channel thread\n"); 01980 return -1; 01981 } 01982 return 0; 01983 } 01984 01985 /* 01986 * This function locks contexts list by &conlist, search for the right context 01987 * structure, leave context list locked and call ast_context_remove_include2 01988 * which removes include, unlock contexts list and return ... 01989 */ 01990 int ast_context_remove_include(char *context, char *include, char *registrar) 01991 { 01992 struct ast_context *c; 01993 01994 if (ast_lock_contexts()) return -1; 01995 01996 /* walk contexts and search for the right one ...*/ 01997 c = ast_walk_contexts(NULL); 01998 while (c) { 01999 /* we found one ... */ 02000 if (!strcmp(ast_get_context_name(c), context)) { 02001 int ret; 02002 /* remove include from this context ... */ 02003 ret = ast_context_remove_include2(c, include, registrar); 02004 02005 ast_unlock_contexts(); 02006 02007 /* ... return results */ 02008 return ret; 02009 } 02010 c = ast_walk_contexts(c); 02011 } 02012 02013 /* we can't find the right one context */ 02014 ast_unlock_contexts(); 02015 return -1; 02016 } 02017 02018 /* 02019 * When we call this function, &conlock lock must be locked, because when 02020 * we giving *con argument, some process can remove/change this context 02021 * and after that there can be segfault. 02022 * 02023 * This function locks given context, removes include, unlock context and 02024 * return. 02025 */ 02026 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar) 02027 { 02028 struct ast_include *i, *pi = NULL; 02029 02030 if (ast_mutex_lock(&con->lock)) return -1; 02031 02032 /* walk includes */ 02033 i = con->includes; 02034 while (i) { 02035 /* find our include */ 02036 if (!strcmp(i->name, include) && 02037 (!strcmp(i->registrar, registrar) || !registrar)) { 02038 /* remove from list */ 02039 if (pi) 02040 pi->next = i->next; 02041 else 02042 con->includes = i->next; 02043 /* free include and return */ 02044 free(i); 02045 ast_mutex_unlock(&con->lock); 02046 return 0; 02047 } 02048 pi = i; 02049 i = i->next; 02050 } 02051 02052 /* we can't find the right include */ 02053 ast_mutex_unlock(&con->lock); 02054 return -1; 02055 } 02056 02057 /* 02058 * This function locks contexts list by &conlist, search for the rigt context 02059 * structure, leave context list locked and call ast_context_remove_switch2 02060 * which removes switch, unlock contexts list and return ... 02061 */ 02062 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar) 02063 { 02064 struct ast_context *c; 02065 02066 if (ast_lock_contexts()) return -1; 02067 02068 /* walk contexts and search for the right one ...*/ 02069 c = ast_walk_contexts(NULL); 02070 while (c) { 02071 /* we found one ... */ 02072 if (!strcmp(ast_get_context_name(c), context)) { 02073 int ret; 02074 /* remove switch from this context ... */ 02075 ret = ast_context_remove_switch2(c, sw, data, registrar); 02076 02077 ast_unlock_contexts(); 02078 02079 /* ... return results */ 02080 return ret; 02081 } 02082 c = ast_walk_contexts(c); 02083 } 02084 02085 /* we can't find the right one context */ 02086 ast_unlock_contexts(); 02087 return -1; 02088 } 02089 02090 /* 02091 * When we call this function, &conlock lock must be locked, because when 02092 * we giving *con argument, some process can remove/change this context 02093 * and after that there can be segfault. 02094 * 02095 * This function locks given context, removes switch, unlock context and 02096 * return. 02097 */ 02098 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar) 02099 { 02100 struct ast_sw *i, *pi = NULL; 02101 02102 if (ast_mutex_lock(&con->lock)) return -1; 02103 02104 /* walk switchs */ 02105 i = con->alts; 02106 while (i) { 02107 /* find our switch */ 02108 if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 02109 (!strcmp(i->registrar, registrar) || !registrar)) { 02110 /* remove from list */ 02111 if (pi) 02112 pi->next = i->next; 02113 else 02114 con->alts = i->next; 02115 /* free switch and return */ 02116 free(i); 02117 ast_mutex_unlock(&con->lock); 02118 return 0; 02119 } 02120 pi = i; 02121 i = i->next; 02122 } 02123 02124 /* we can't find the right switch */ 02125 ast_mutex_unlock(&con->lock); 02126 return -1; 02127 } 02128 02129 /* 02130 * This functions lock contexts list, search for the right context, 02131 * call ast_context_remove_extension2, unlock contexts list and return. 02132 * In this function we are using 02133 */ 02134 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar) 02135 { 02136 struct ast_context *c; 02137 02138 if (ast_lock_contexts()) return -1; 02139 02140 /* walk contexts ... */ 02141 c = ast_walk_contexts(NULL); 02142 while (c) { 02143 /* ... search for the right one ... */ 02144 if (!strcmp(ast_get_context_name(c), context)) { 02145 /* ... remove extension ... */ 02146 int ret = ast_context_remove_extension2(c, extension, priority, 02147 registrar); 02148 /* ... unlock contexts list and return */ 02149 ast_unlock_contexts(); 02150 return ret; 02151 } 02152 c = ast_walk_contexts(c); 02153 } 02154 02155 /* we can't find the right context */ 02156 ast_unlock_contexts(); 02157 return -1; 02158 } 02159 02160 /* 02161 * When do you want to call this function, make sure that &conlock is locked, 02162 * because some process can handle with your *con context before you lock 02163 * it. 02164 * 02165 * This functionc locks given context, search for the right extension and 02166 * fires out all peer in this extensions with given priority. If priority 02167 * is set to 0, all peers are removed. After that, unlock context and 02168 * return. 02169 */ 02170 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar) 02171 { 02172 struct ast_exten *exten, *prev_exten = NULL; 02173 02174 if (ast_mutex_lock(&con->lock)) return -1; 02175 02176 /* go through all extensions in context and search the right one ... */ 02177 exten = con->root; 02178 while (exten) { 02179 02180 /* look for right extension */ 02181 if (!strcmp(exten->exten, extension) && 02182 (!strcmp(exten->registrar, registrar) || !registrar)) { 02183 struct ast_exten *peer; 02184 02185 /* should we free all peers in this extension? (priority == 0)? */ 02186 if (priority == 0) { 02187 /* remove this extension from context list */ 02188 if (prev_exten) 02189 prev_exten->next = exten->next; 02190 else 02191 con->root = exten->next; 02192 02193 /* fire out all peers */ 02194 peer = exten; 02195 while (peer) { 02196 exten = peer->peer; 02197 02198 if (!peer->priority==PRIORITY_HINT) 02199 ast_remove_hint(peer); 02200 02201 peer->datad(peer->data); 02202 free(peer); 02203 02204 peer = exten; 02205 } 02206 02207 ast_mutex_unlock(&con->lock); 02208 return 0; 02209 } else { 02210 /* remove only extension with exten->priority == priority */ 02211 struct ast_exten *previous_peer = NULL; 02212 02213 peer = exten; 02214 while (peer) { 02215 /* is this our extension? */ 02216 if (peer->priority == priority && 02217 (!strcmp(peer->registrar, registrar) || !registrar)) { 02218 /* we are first priority extension? */ 02219 if (!previous_peer) { 02220 /* exists previous extension here? */ 02221 if (prev_exten) { 02222 /* yes, so we must change next pointer in 02223 * previous connection to next peer 02224 */ 02225 if (peer->peer) { 02226 prev_exten->next = peer->peer; 02227 peer->peer->next = exten->next; 02228 } else 02229 prev_exten->next = exten->next; 02230 } else { 02231 /* no previous extension, we are first 02232 * extension, so change con->root ... 02233 */ 02234 if (peer->peer) 02235 con->root = peer->peer; 02236 else 02237 con->root = exten->next; 02238 } 02239 } else { 02240 /* we are not first priority in extension */ 02241 previous_peer->peer = peer->peer; 02242 } 02243 02244 /* now, free whole priority extension */ 02245 if (peer->priority==PRIORITY_HINT) 02246 ast_remove_hint(peer); 02247 peer->datad(peer->data); 02248 free(peer); 02249 02250 ast_mutex_unlock(&con->lock); 02251 return 0; 02252 } else { 02253 /* this is not right extension, skip to next peer */ 02254 previous_peer = peer; 02255 peer = peer->peer; 02256 } 02257 } 02258 02259 ast_mutex_unlock(&con->lock); 02260 return -1; 02261 } 02262 } 02263 02264 prev_exten = exten; 02265 exten = exten->next; 02266 } 02267 02268 /* we can't find right extension */ 02269 ast_mutex_unlock(&con->lock); 02270 return -1; 02271 } 02272 02273 02274 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description) 02275 { 02276 struct ast_app *tmp, *prev, *cur; 02277 char tmps[80]; 02278 if (ast_mutex_lock(&applock)) { 02279 ast_log(LOG_ERROR, "Unable to lock application list\n"); 02280 return -1; 02281 } 02282 tmp = apps; 02283 while(tmp) { 02284 if (!strcasecmp(app, tmp->name)) { 02285 ast_log(LOG_WARNING, "Already have an application '%s'\n", app); 02286 ast_mutex_unlock(&applock); 02287 return -1; 02288 } 02289 tmp = tmp->next; 02290 } 02291 tmp = malloc(sizeof(struct ast_app)); 02292 if (tmp) { 02293 memset(tmp, 0, sizeof(struct ast_app)); 02294 strncpy(tmp->name, app, sizeof(tmp->name)-1); 02295 tmp->execute = execute; 02296 tmp->synopsis = synopsis; 02297 tmp->description = description; 02298 /* Store in alphabetical order */ 02299 cur = apps; 02300 prev = NULL; 02301 while(cur) { 02302 if (strcasecmp(tmp->name, cur->name) < 0) 02303 break; 02304 prev = cur; 02305 cur = cur->next; 02306 } 02307 if (prev) { 02308 tmp->next = prev->next; 02309 prev->next = tmp; 02310 } else { 02311 tmp->next = apps; 02312 apps = tmp; 02313 } 02314 } else { 02315 ast_log(LOG_ERROR, "Out of memory\n"); 02316 ast_mutex_unlock(&applock); 02317 return -1; 02318 } 02319 if (option_verbose > 1) 02320 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps))); 02321 ast_mutex_unlock(&applock); 02322 return 0; 02323 } 02324 02325 int ast_register_switch(struct ast_switch *sw) 02326 { 02327 struct ast_switch *tmp, *prev=NULL; 02328 if (ast_mutex_lock(&switchlock)) { 02329 ast_log(LOG_ERROR, "Unable to lock switch lock\n"); 02330 return -1; 02331 } 02332 tmp = switches; 02333 while(tmp) { 02334 if (!strcasecmp(tmp->name, sw->name)) 02335 break; 02336 prev = tmp; 02337 tmp = tmp->next; 02338 } 02339 if (tmp) { 02340 ast_mutex_unlock(&switchlock); 02341 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name); 02342 return -1; 02343 } 02344 sw->next = NULL; 02345 if (prev) 02346 prev->next = sw; 02347 else 02348 switches = sw; 02349 ast_mutex_unlock(&switchlock); 02350 return 0; 02351 } 02352 02353 void ast_unregister_switch(struct ast_switch *sw) 02354 { 02355 struct ast_switch *tmp, *prev=NULL; 02356 if (ast_mutex_lock(&switchlock)) { 02357 ast_log(LOG_ERROR, "Unable to lock switch lock\n"); 02358 return; 02359 } 02360 tmp = switches; 02361 while(tmp) { 02362 if (tmp == sw) { 02363 if (prev) 02364 prev->next = tmp->next; 02365 else 02366 switches = tmp->next; 02367 tmp->next = NULL; 02368 break; 02369 } 02370 prev = tmp; 02371 tmp = tmp->next; 02372 } 02373 ast_mutex_unlock(&switchlock); 02374 } 02375 02376 /* 02377 * Help for CLI commands ... 02378 */ 02379 static char show_application_help[] = 02380 "Usage: show application <application> [<application> [<application> [...]]]\n" 02381 " Describes a particular application.\n"; 02382 02383 static char show_applications_help[] = 02384 "Usage: show applications\n" 02385 " List applications which are currently available.\n"; 02386 02387 static char show_dialplan_help[] = 02388 "Usage: show dialplan [exten@][context]\n" 02389 " Show dialplan\n"; 02390 02391 static char show_switches_help[] = 02392 "Usage: show switches\n" 02393 " Show registered switches\n"; 02394 02395 /* 02396 * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS 02397 * 02398 */ 02399 02400 /* 02401 * 'show application' CLI command implementation functions ... 02402 */ 02403 02404 /* 02405 * There is a possibility to show informations about more than one 02406 * application at one time. You can type 'show application Dial Echo' and 02407 * you will see informations about these two applications ... 02408 */ 02409 static char *complete_show_application(char *line, char *word, 02410 int pos, int state) 02411 { 02412 struct ast_app *a; 02413 int which = 0; 02414 02415 /* try to lock applications list ... */ 02416 if (ast_mutex_lock(&applock)) { 02417 ast_log(LOG_ERROR, "Unable to lock application list\n"); 02418 return NULL; 02419 } 02420 02421 /* ... walk all applications ... */ 02422 a = apps; 02423 while (a) { 02424 /* ... check if word matches this application ... */ 02425 if (!strncasecmp(word, a->name, strlen(word))) { 02426 /* ... if this is right app serve it ... */ 02427 if (++which > state) { 02428 char *ret = strdup(a->name); 02429 ast_mutex_unlock(&applock); 02430 return ret; 02431 } 02432 } 02433 a = a->next; 02434 } 02435 02436 /* no application match */ 02437 ast_mutex_unlock(&applock); 02438 return NULL; 02439 } 02440 02441 static int handle_show_application(int fd, int argc, char *argv[]) 02442 { 02443 struct ast_app *a; 02444 int app, no_registered_app = 1; 02445 02446 if (argc < 3) return RESULT_SHOWUSAGE; 02447 02448 /* try to lock applications list ... */ 02449 if (ast_mutex_lock(&applock)) { 02450 ast_log(LOG_ERROR, "Unable to lock application list\n"); 02451 return -1; 02452 } 02453 02454 /* ... go through all applications ... */ 02455 a = apps; 02456 while (a) { 02457 /* ... compare this application name with all arguments given 02458 * to 'show application' command ... */ 02459 for (app = 2; app < argc; app++) { 02460 if (!strcasecmp(a->name, argv[app])) { 02461 /* Maximum number of characters added by terminal coloring is 22 */ 02462 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40]; 02463 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL; 02464 int synopsis_size, description_size; 02465 02466 no_registered_app = 0; 02467 02468 if (a->synopsis) 02469 synopsis_size = strlen(a->synopsis) + 23; 02470 else 02471 synopsis_size = strlen("Not available") + 23; 02472 synopsis = alloca(synopsis_size); 02473 02474 if (a->description) 02475 description_size = strlen(a->description) + 23; 02476 else 02477 description_size = strlen("Not available") + 23; 02478 description = alloca(description_size); 02479 02480 if (synopsis && description) { 02481 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name); 02482 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22); 02483 term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40); 02484 term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40); 02485 term_color(synopsis, 02486 a->synopsis ? a->synopsis : "Not available", 02487 COLOR_CYAN, 0, synopsis_size); 02488 term_color(description, 02489 a->description ? a->description : "Not available", 02490 COLOR_CYAN, 0, description_size); 02491 02492 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description); 02493 } else { 02494 /* ... one of our applications, show info ...*/ 02495 ast_cli(fd,"\n -= Info about application '%s' =- \n\n" 02496 "[Synopsis]:\n %s\n\n" 02497 "[Description]:\n%s\n", 02498 a->name, 02499 a->synopsis ? a->synopsis : "Not available", 02500 a->description ? a->description : "Not available"); 02501 } 02502 } 02503 } 02504 a = a->next; 02505 } 02506 02507 ast_mutex_unlock(&applock); 02508 02509 /* we found at least one app? no? */ 02510 if (no_registered_app) { 02511 ast_cli(fd, "Your application(s) is (are) not registered\n"); 02512 return RESULT_FAILURE; 02513 } 02514 02515 return RESULT_SUCCESS; 02516 } 02517 02518 static int handle_show_switches(int fd, int argc, char *argv[]) 02519 { 02520 struct ast_switch *sw; 02521 if (!switches) { 02522 ast_cli(fd, "There are no registered alternative switches\n"); 02523 return RESULT_SUCCESS; 02524 } 02525 /* ... we have applications ... */ 02526 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n"); 02527 if (ast_mutex_lock(&switchlock)) { 02528 ast_log(LOG_ERROR, "Unable to lock switches\n"); 02529 return -1; 02530 } 02531 sw = switches; 02532 while (sw) { 02533 ast_cli(fd, "%s: %s\n", sw->name, sw->description); 02534 sw = sw->next; 02535 } 02536 ast_mutex_unlock(&switchlock); 02537 return RESULT_SUCCESS; 02538 } 02539 02540 /* 02541 * 'show applications' CLI command implementation functions ... 02542 */ 02543 static int handle_show_applications(int fd, int argc, char *argv[]) 02544 { 02545 struct ast_app *a; 02546 02547 /* try to lock applications list ... */ 02548 if (ast_mutex_lock(&applock)) { 02549 ast_log(LOG_ERROR, "Unable to lock application list\n"); 02550 return -1; 02551 } 02552 02553 /* ... go to first application ... */ 02554 a = apps; 02555 02556 /* ... have we got at least one application (first)? no? */ 02557 if (!a) { 02558 ast_cli(fd, "There is no registered applications\n"); 02559 ast_mutex_unlock(&applock); 02560 return -1; 02561 } 02562 02563 /* ... we have applications ... */ 02564 ast_cli(fd, "\n -= Registered Asterisk Applications =-\n"); 02565 02566 /* ... go through all applications ... */ 02567 while (a) { 02568 /* ... show informations about applications ... */ 02569 ast_cli(fd," %20s: %s\n", 02570 a->name, 02571 a->synopsis ? a->synopsis : "<Synopsis not available>"); 02572 a = a->next; 02573 } 02574 02575 /* ... unlock and return */ 02576 ast_mutex_unlock(&applock); 02577 02578 return RESULT_SUCCESS; 02579 } 02580 02581 /* 02582 * 'show dialplan' CLI command implementation functions ... 02583 */ 02584 static char *complete_show_dialplan_context(char *line, char *word, int pos, 02585 int state) 02586 { 02587 struct ast_context *c; 02588 int which = 0; 02589 02590 /* we are do completion of [exten@]context on second position only */ 02591 if (pos != 2) return NULL; 02592 02593 /* try to lock contexts list ... */ 02594 if (ast_lock_contexts()) { 02595 ast_log(LOG_ERROR, "Unable to lock context list\n"); 02596 return NULL; 02597 } 02598 02599 /* ... walk through all contexts ... */ 02600 c = ast_walk_contexts(NULL); 02601 while(c) { 02602 /* ... word matches context name? yes? ... */ 02603 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) { 02604 /* ... for serve? ... */ 02605 if (++which > state) { 02606 /* ... yes, serve this context name ... */ 02607 char *ret = strdup(ast_get_context_name(c)); 02608 ast_unlock_contexts(); 02609 return ret; 02610 } 02611 } 02612 c = ast_walk_contexts(c); 02613 } 02614 02615 /* ... unlock and return */ 02616 ast_unlock_contexts(); 02617 return NULL; 02618 } 02619 02620 static int handle_show_dialplan(int fd, int argc, char *argv[]) 02621 { 02622 struct ast_context *c; 02623 char *exten = NULL, *context = NULL; 02624 int context_existence = 0, extension_existence = 0; 02625 02626 if (argc != 3 && argc != 2) return -1; 02627 02628 /* we obtain [exten@]context? if yes, split them ... */ 02629 if (argc == 3) { 02630 char *splitter = argv[2]; 02631 /* is there a '@' character? */ 02632 if (strchr(argv[2], '@')) { 02633 /* yes, split into exten & context ... */ 02634 exten = strsep(&splitter, "@"); 02635 context = splitter; 02636 02637 /* check for length and change to NULL if ast_strlen_zero() */ 02638 if (ast_strlen_zero(exten)) exten = NULL; 02639 if (ast_strlen_zero(context)) context = NULL; 02640 } else 02641 { 02642 /* no '@' char, only context given */ 02643 context = argv[2]; 02644 if (ast_strlen_zero(context)) context = NULL; 02645 } 02646 } 02647 02648 /* try to lock contexts */ 02649 if (ast_lock_contexts()) { 02650 ast_log(LOG_WARNING, "Failed to lock contexts list\n"); 02651 return RESULT_FAILURE; 02652 } 02653 02654 /* walk all contexts ... */ 02655 c = ast_walk_contexts(NULL); 02656 while (c) { 02657 /* show this context? */ 02658 if (!context || 02659 !strcmp(ast_get_context_name(c), context)) { 02660 context_existence = 1; 02661 02662 /* try to lock context before walking in ... */ 02663 if (!ast_lock_context(c)) { 02664 struct ast_exten *e; 02665 struct ast_include *i; 02666 struct ast_ignorepat *ip; 02667 struct ast_sw *sw; 02668 char buf[256], buf2[256]; 02669 int context_info_printed = 0; 02670 02671 /* are we looking for exten too? if yes, we print context 02672 * if we our extension only 02673 */ 02674 if (!exten) { 02675 ast_cli(fd, "[ Context '%s' created by '%s' ]\n", 02676 ast_get_context_name(c), ast_get_context_registrar(c)); 02677 context_info_printed = 1; 02678 } 02679 02680 /* walk extensions ... */ 02681 e = ast_walk_context_extensions(c, NULL); 02682 while (e) { 02683 struct ast_exten *p; 02684 02685 /* looking for extension? is this our extension? */ 02686 if (exten && 02687 strcmp(ast_get_extension_name(e), exten)) 02688 { 02689 /* we are looking for extension and it's not our 02690 * extension, so skip to next extension */ 02691 e = ast_walk_context_extensions(c, e); 02692 continue; 02693 } 02694 02695 extension_existence = 1; 02696 02697 /* may we print context info? */ 02698 if (!context_info_printed) { 02699 ast_cli(fd, "[ Context '%s' created by '%s' ]\n", 02700 ast_get_context_name(c), 02701 ast_get_context_registrar(c)); 02702 context_info_printed = 1; 02703 } 02704 02705 /* write extension name and first peer */ 02706 bzero(buf, sizeof(buf)); 02707 snprintf(buf, sizeof(buf), "'%s' =>", 02708 ast_get_extension_name(e)); 02709 02710 snprintf(buf2, sizeof(buf2), 02711 "%d. %s(%s)", 02712 ast_get_extension_priority(e), 02713 ast_get_extension_app(e), 02714 (char *)ast_get_extension_app_data(e)); 02715 02716 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2, 02717 ast_get_extension_registrar(e)); 02718 02719 /* walk next extension peers */ 02720 p = ast_walk_extension_priorities(e, e); 02721 while (p) { 02722 bzero((void *)buf2, sizeof(buf2)); 02723 02724 snprintf(buf2, sizeof(buf2), 02725 "%d. %s(%s)", 02726 ast_get_extension_priority(p), 02727 ast_get_extension_app(p), 02728 (char *)ast_get_extension_app_data(p)); 02729 02730 ast_cli(fd," %-17s %-45s [%s]\n", 02731 "", buf2, 02732 ast_get_extension_registrar(p)); 02733 02734 p = ast_walk_extension_priorities(e, p); 02735 } 02736 e = ast_walk_context_extensions(c, e); 02737 } 02738 02739 /* include & ignorepat we all printing if we are not 02740 * looking for exact extension 02741 */ 02742 if (!exten) { 02743 if (ast_walk_context_extensions(c, NULL)) 02744 ast_cli(fd, "\n"); 02745 02746 /* walk included and write info ... */ 02747 i = ast_walk_context_includes(c, NULL); 02748 while (i) { 02749 bzero(buf, sizeof(buf)); 02750 snprintf(buf, sizeof(buf), "'%s'", 02751 ast_get_include_name(i)); 02752 ast_cli(fd, " Include => %-45s [%s]\n", 02753 buf, ast_get_include_registrar(i)); 02754 i = ast_walk_context_includes(c, i); 02755 } 02756 02757 /* walk ignore patterns and write info ... */ 02758 ip = ast_walk_context_ignorepats(c, NULL); 02759 while (ip) { 02760 bzero(buf, sizeof(buf)); 02761 snprintf(buf, sizeof(buf), "'%s'", 02762 ast_get_ignorepat_name(ip)); 02763 ast_cli(fd, " Ignore pattern => %-45s [%s]\n", 02764 buf, ast_get_ignorepat_registrar(ip)); 02765 ip = ast_walk_context_ignorepats(c, ip); 02766 } 02767 sw = ast_walk_context_switches(c, NULL); 02768 while(sw) { 02769 bzero(buf, sizeof(buf)); 02770 snprintf(buf, sizeof(buf), "'%s/%s'", 02771 ast_get_switch_name(sw), 02772 ast_get_switch_data(sw)); 02773 ast_cli(fd, " Alt. Switch => %-45s [%s]\n", 02774 buf, ast_get_switch_registrar(sw)); 02775 sw = ast_walk_context_switches(c, sw); 02776 } 02777 } 02778 02779 ast_unlock_context(c); 02780 02781 /* if we print something in context, make an empty line */ 02782 if (context_info_printed) ast_cli(fd, "\n"); 02783 } 02784 } 02785 c = ast_walk_contexts(c); 02786 } 02787 ast_unlock_contexts(); 02788 02789 /* check for input failure and throw some error messages */ 02790 if (context && !context_existence) { 02791 ast_cli(fd, "There is no existence of '%s' context\n", 02792 context); 02793 return RESULT_FAILURE; 02794 } 02795 02796 if (exten && !extension_existence) { 02797 if (context) 02798 ast_cli(fd, "There is no existence of %s@%s extension\n", 02799 exten, context); 02800 else 02801 ast_cli(fd, 02802 "There is no existence of '%s' extension in all contexts\n", 02803 exten); 02804 return RESULT_FAILURE; 02805 } 02806 02807 /* everything ok */ 02808 return RESULT_SUCCESS; 02809 } 02810 02811 /* 02812 * CLI entries for upper commands ... 02813 */ 02814 static struct ast_cli_entry show_applications_cli = 02815 { { "show", "applications", NULL }, 02816 handle_show_applications, "Shows registered applications", 02817 show_applications_help }; 02818 02819 static struct ast_cli_entry show_application_cli = 02820 { { "show", "application", NULL }, 02821 handle_show_application, "Describe a specific application", 02822 show_application_help, complete_show_application }; 02823 02824 static struct ast_cli_entry show_dialplan_cli = 02825 { { "show", "dialplan", NULL }, 02826 handle_show_dialplan, "Show dialplan", 02827 show_dialplan_help, complete_show_dialplan_context }; 02828 02829 static struct ast_cli_entry show_switches_cli = 02830 { { "show", "switches", NULL }, 02831 handle_show_switches, "Show alternative switches", 02832 show_switches_help, NULL }; 02833 02834 int ast_unregister_application(char *app) { 02835 struct ast_app *tmp, *tmpl = NULL; 02836 if (ast_mutex_lock(&applock)) { 02837 ast_log(LOG_ERROR, "Unable to lock application list\n"); 02838 return -1; 02839 } 02840 tmp = apps; 02841 while(tmp) { 02842 if (!strcasecmp(app, tmp->name)) { 02843 if (tmpl) 02844 tmpl->next = tmp->next; 02845 else 02846 apps = tmp->next; 02847 if (option_verbose > 1) 02848 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name); 02849 ast_mutex_unlock(&applock); 02850 return 0; 02851 } 02852 tmpl = tmp; 02853 tmp = tmp->next; 02854 } 02855 ast_mutex_unlock(&applock); 02856 return -1; 02857 } 02858 02859 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar) 02860 { 02861 struct ast_context *tmp, **local_contexts; 02862 if (!extcontexts) { 02863 local_contexts = &contexts; 02864 ast_mutex_lock(&conlock); 02865 } else 02866 local_contexts = extcontexts; 02867 02868 tmp = *local_contexts; 02869 while(tmp) { 02870 if (!strcasecmp(tmp->name, name)) { 02871 ast_mutex_unlock(&conlock); 02872 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name); 02873 if (!extcontexts) 02874 ast_mutex_unlock(&conlock); 02875 return NULL; 02876 } 02877 tmp = tmp->next; 02878 } 02879 tmp = malloc(sizeof(struct ast_context)); 02880 if (tmp) { 02881 memset(tmp, 0, sizeof(struct ast_context)); 02882 ast_mutex_init(&tmp->lock); 02883 strncpy(tmp->name, name, sizeof(tmp->name)-1); 02884 tmp->root = NULL; 02885 tmp->registrar = registrar; 02886 tmp->next = *local_contexts; 02887 tmp->includes = NULL; 02888 tmp->ignorepats = NULL; 02889 *local_contexts = tmp; 02890 if (option_debug) 02891 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name); 02892 else if (option_verbose > 2) 02893 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name); 02894 } else 02895 ast_log(LOG_ERROR, "Out of memory\n"); 02896 02897 if (!extcontexts) 02898 ast_mutex_unlock(&conlock); 02899 return tmp; 02900 } 02901 02902 void __ast_context_destroy(struct ast_context *con, char *registrar); 02903 02904 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) { 02905 struct ast_context *tmp, *lasttmp = NULL; 02906 tmp = *extcontexts; 02907 ast_mutex_lock(&conlock); 02908 if (registrar) { 02909 __ast_context_destroy(NULL,registrar); 02910 while (tmp) { 02911 lasttmp = tmp; 02912 tmp = tmp->next; 02913 } 02914 } else { 02915 while (tmp) { 02916 __ast_context_destroy(tmp,tmp->registrar); 02917 lasttmp = tmp; 02918 tmp = tmp->next; 02919 } 02920 } 02921 if (lasttmp) { 02922 lasttmp->next = contexts; 02923 contexts = *extcontexts; 02924 *extcontexts = NULL; 02925 } else 02926 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n"); 02927 ast_mutex_unlock(&conlock); 02928 return; 02929 } 02930 02931 /* 02932 * errno values 02933 * EBUSY - can't lock 02934 * ENOENT - no existence of context 02935 */ 02936 int ast_context_add_include(char *context, char *include, char *registrar) 02937 { 02938 struct ast_context *c; 02939 02940 if (ast_lock_contexts()) { 02941 errno = EBUSY; 02942 return -1; 02943 } 02944 02945 /* walk contexts ... */ 02946 c = ast_walk_contexts(NULL); 02947 while (c) { 02948 /* ... search for the right one ... */ 02949 if (!strcmp(ast_get_context_name(c), context)) { 02950 int ret = ast_context_add_include2(c, include, registrar); 02951 /* ... unlock contexts list and return */ 02952 ast_unlock_contexts(); 02953 return ret; 02954 } 02955 c = ast_walk_contexts(c); 02956 } 02957 02958 /* we can't find the right context */ 02959 ast_unlock_contexts(); 02960 errno = ENOENT; 02961 return -1; 02962 } 02963 02964 #define FIND_NEXT \ 02965 do { \ 02966 c = info; \ 02967 while(*c && (*c != '|')) c++; \ 02968 if (*c) { *c = '\0'; c++; } else c = NULL; \ 02969 } while(0) 02970 02971 static void get_timerange(struct ast_include *i, char *times) 02972 { 02973 char *e; 02974 int x; 02975 int s1, s2; 02976 int e1, e2; 02977 /* int cth, ctm; */ 02978 02979 /* start disabling all times, fill the fields with 0's, as they may contain garbage */ 02980 memset(i->minmask, 0, sizeof(i->minmask)); 02981 02982 /* Star is all times */ 02983 if (ast_strlen_zero(times) || !strcmp(times, "*")) { 02984 for (x=0;x<24;x++) 02985 i->minmask[x] = (1 << 30) - 1; 02986 return; 02987 } 02988 /* Otherwise expect a range */ 02989 e = strchr(times, '-'); 02990 if (!e) { 02991 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n"); 02992 return; 02993 } 02994 *e = '\0'; 02995 e++; 02996 while(*e && !isdigit(*e)) e++; 02997 if (!*e) { 02998 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n"); 02999 return; 03000 } 03001 if (sscanf(times, "%d:%d", &s1, &s2) != 2) { 03002 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times); 03003 return; 03004 } 03005 if (sscanf(e, "%d:%d", &e1, &e2) != 2) { 03006 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e); 03007 return; 03008 } 03009 03010 #if 1 03011 s1 = s1 * 30 + s2/2; 03012 if ((s1 < 0) || (s1 >= 24*30)) { 03013 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times); 03014 return; 03015 } 03016 e1 = e1 * 30 + e2/2; 03017 if ((e1 < 0) || (e1 >= 24*30)) { 03018 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e); 03019 return; 03020 } 03021 /* Go through the time and enable each appropriate bit */ 03022 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) { 03023 i->minmask[x/30] |= (1 << (x % 30)); 03024 } 03025 /* Do the last one */ 03026 i->minmask[x/30] |= (1 << (x % 30)); 03027 #else 03028 for (cth=0;cth<24;cth++) { 03029 /* Initialize masks to blank */ 03030 i->minmask[cth] = 0; 03031 for (ctm=0;ctm<30;ctm++) { 03032 if ( 03033 /* First hour with more than one hour */ 03034 (((cth == s1) && (ctm >= s2)) && 03035 ((cth < e1))) 03036 /* Only one hour */ 03037 || (((cth == s1) && (ctm >= s2)) && 03038 ((cth == e1) && (ctm <= e2))) 03039 /* In between first and last hours (more than 2 hours) */ 03040 || ((cth > s1) && 03041 (cth < e1)) 03042 /* Last hour with more than one hour */ 03043 || ((cth > s1) && 03044 ((cth == e1) && (ctm <= e2))) 03045 ) 03046 i->minmask[cth] |= (1 << (ctm / 2)); 03047 } 03048 } 03049 #endif 03050 /* All done */ 03051 return; 03052 } 03053 03054 static char *days[] = 03055 { 03056 "sun", 03057 "mon", 03058 "tue", 03059 "wed", 03060 "thu", 03061 "fri", 03062 "sat", 03063 }; 03064 03065 static unsigned int get_dow(char *dow) 03066 { 03067 char *c; 03068 /* The following line is coincidence, really! */ 03069 int s, e, x; 03070 unsigned int mask; 03071 03072 /* Check for all days */ 03073 if (ast_strlen_zero(dow) || !strcmp(dow, "*")) 03074 return (1 << 7) - 1; 03075 /* Get start and ending days */ 03076 c = strchr(dow, '-'); 03077 if (c) { 03078 *c = '\0'; 03079 c++; 03080 } else 03081 c = NULL; 03082 /* Find the start */ 03083 s = 0; 03084 while((s < 7) && strcasecmp(dow, days[s])) s++; 03085 if (s >= 7) { 03086 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow); 03087 return 0; 03088 } 03089 if (c) { 03090 e = 0; 03091 while((e < 7) && strcasecmp(c, days[e])) e++; 03092 if (e >= 7) { 03093 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c); 03094 return 0; 03095 } 03096 } else 03097 e = s; 03098 mask = 0; 03099 for (x=s; x != e; x = (x + 1) % 7) { 03100 mask |= (1 << x); 03101 } 03102 /* One last one */ 03103 mask |= (1 << x); 03104 return mask; 03105 } 03106 03107 static unsigned int get_day(char *day) 03108 { 03109 char *c; 03110 /* The following line is coincidence, really! */ 03111 int s, e, x; 03112 unsigned int mask; 03113 03114 /* Check for all days */ 03115 if (ast_strlen_zero(day) || !strcmp(day, "*")) { 03116 mask = (1 << 30) + ((1 << 30) - 1); 03117 return mask; 03118 } 03119 /* Get start and ending days */ 03120 c = strchr(day, '-'); 03121 if (c) { 03122 *c = '\0'; 03123 c++; 03124 } 03125 /* Find the start */ 03126 if (sscanf(day, "%d", &s) != 1) { 03127 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day); 03128 return 0; 03129 } 03130 if ((s < 1) || (s > 31)) { 03131 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day); 03132 return 0; 03133 } 03134 s--; 03135 if (c) { 03136 if (sscanf(c, "%d", &e) != 1) { 03137 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c); 03138 return 0; 03139 } 03140 if ((e < 1) || (e > 31)) { 03141 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c); 03142 return 0; 03143 } 03144 e--; 03145 } else 03146 e = s; 03147 mask = 0; 03148 for (x=s;x!=e;x = (x + 1) % 31) { 03149 mask |= (1 << x); 03150 } 03151 mask |= (1 << x); 03152 return mask; 03153 } 03154 03155 static char *months[] = 03156 { 03157 "jan", 03158 "feb", 03159 "mar", 03160 "apr", 03161 "may", 03162 "jun", 03163 "jul", 03164 "aug", 03165 "sep", 03166 "oct", 03167 "nov", 03168 "dec", 03169 }; 03170 03171 static unsigned int get_month(char *mon) 03172 { 03173 char *c; 03174 /* The following line is coincidence, really! */ 03175 int s, e, x; 03176 unsigned int mask; 03177 03178 /* Check for all days */ 03179 if (ast_strlen_zero(mon) || !strcmp(mon, "*")) 03180 return (1 << 12) - 1; 03181 /* Get start and ending days */ 03182 c = strchr(mon, '-'); 03183 if (c) { 03184 *c = '\0'; 03185 c++; 03186 } 03187 /* Find the start */ 03188 s = 0; 03189 while((s < 12) && strcasecmp(mon, months[s])) s++; 03190 if (s >= 12) { 03191 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon); 03192 return 0; 03193 } 03194 if (c) { 03195 e = 0; 03196 while((e < 12) && strcasecmp(mon, months[e])) e++; 03197 if (e >= 12) { 03198 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c); 03199 return 0; 03200 } 03201 } else 03202 e = s; 03203 mask = 0; 03204 for (x=s; x!=e; x = (x + 1) % 12) { 03205 mask |= (1 << x); 03206 } 03207 /* One last one */ 03208 mask |= (1 << x); 03209 return mask; 03210 } 03211 03212 static void build_timing(struct ast_include *i, char *info) 03213 { 03214 char *c; 03215 03216 /* Check for empty just in case */ 03217 if (ast_strlen_zero(info)) 03218 return; 03219 i->hastime = 1; 03220 /* Assume everything except time */ 03221 i->monthmask = (1 << 12) - 1; 03222 i->daymask = (1 << 30) - 1 + (1 << 30); 03223 i->dowmask = (1 << 7) - 1; 03224 /* Avoid using str tok */ 03225 FIND_NEXT; 03226 /* Info has the time range, start with that */ 03227 get_timerange(i, info); 03228 info = c; 03229 if (!info) 03230 return; 03231 FIND_NEXT; 03232 /* Now check for day of week */ 03233 i->dowmask = get_dow(info); 03234 03235 info = c; 03236 if (!info) 03237 return; 03238 FIND_NEXT; 03239 /* Now check for the day of the month */ 03240 i->daymask = get_day(info); 03241 info = c; 03242 if (!info) 03243 return; 03244 FIND_NEXT; 03245 /* And finally go for the month */ 03246 i->monthmask = get_month(info); 03247 } 03248 03249 /* 03250 * errno values 03251 * ENOMEM - out of memory 03252 * EBUSY - can't lock 03253 * EEXIST - already included 03254 * EINVAL - there is no existence of context for inclusion 03255 */ 03256 int ast_context_add_include2(struct ast_context *con, char *value, 03257 char *registrar) 03258 { 03259 struct ast_include *new_include; 03260 char *c; 03261 struct ast_include *i, *il = NULL; /* include, include_last */ 03262 03263 /* allocate new include structure ... */ 03264 if (!(new_include = malloc(sizeof(struct ast_include)))) { 03265 ast_log(LOG_ERROR, "Out of memory\n"); 03266 errno = ENOMEM; 03267 return -1; 03268 } 03269 03270 /* ... fill in this structure ... */ 03271 memset(new_include, 0, sizeof(struct ast_include)); 03272 strncpy(new_include->name, value, sizeof(new_include->name)-1); 03273 strncpy(new_include->rname, value, sizeof(new_include->rname)-1); 03274 c = new_include->rname; 03275 /* Strip off timing info */ 03276 while(*c && (*c != '|')) c++; 03277 /* Process if it's there */ 03278 if (*c) { 03279 build_timing(new_include, c+1); 03280 *c = '\0'; 03281 } 03282 new_include->next = NULL; 03283 new_include->registrar = registrar; 03284 03285 /* ... try to lock this context ... */ 03286 if (ast_mutex_lock(&con->lock)) { 03287 free(new_include); 03288 errno = EBUSY; 03289 return -1; 03290 } 03291 03292 /* ... go to last include and check if context is already included too... */ 03293 i = con->includes; 03294 while (i) { 03295 if (!strcasecmp(i->name, new_include->name)) { 03296 free(new_include); 03297 ast_mutex_unlock(&con->lock); 03298 errno = EEXIST; 03299 return -1; 03300 } 03301 il = i; 03302 i = i->next; 03303 } 03304 03305 /* ... include new context into context list, unlock, return */ 03306 if (il) 03307 il->next = new_include; 03308 else 03309 con->includes = new_include; 03310 if (option_verbose > 2) 03311 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 03312 ast_mutex_unlock(&con->lock); 03313 03314 return 0; 03315 } 03316 03317 /* 03318 * errno values 03319 * EBUSY - can't lock 03320 * ENOENT - no existence of context 03321 */ 03322 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar) 03323 { 03324 struct ast_context *c; 03325 03326 if (ast_lock_contexts()) { 03327 errno = EBUSY; 03328 return -1; 03329 } 03330 03331 /* walk contexts ... */ 03332 c = ast_walk_contexts(NULL); 03333 while (c) { 03334 /* ... search for the right one ... */ 03335 if (!strcmp(ast_get_context_name(c), context)) { 03336 int ret = ast_context_add_switch2(c, sw, data, registrar); 03337 /* ... unlock contexts list and return */ 03338 ast_unlock_contexts(); 03339 return ret; 03340 } 03341 c = ast_walk_contexts(c); 03342 } 03343 03344 /* we can't find the right context */ 03345 ast_unlock_contexts(); 03346 errno = ENOENT; 03347 return -1; 03348 } 03349 03350 /* 03351 * errno values 03352 * ENOMEM - out of memory 03353 * EBUSY - can't lock 03354 * EEXIST - already included 03355 * EINVAL - there is no existence of context for inclusion 03356 */ 03357 int ast_context_add_switch2(struct ast_context *con, char *value, 03358 char *data, char *registrar) 03359 { 03360 struct ast_sw *new_sw; 03361 struct ast_sw *i, *il = NULL; /* sw, sw_last */ 03362 03363 /* allocate new sw structure ... */ 03364 if (!(new_sw = malloc(sizeof(struct ast_sw)))) { 03365 ast_log(LOG_ERROR, "Out of memory\n"); 03366 errno = ENOMEM; 03367 return -1; 03368 } 03369 03370 /* ... fill in this structure ... */ 03371 memset(new_sw, 0, sizeof(struct ast_sw)); 03372 strncpy(new_sw->name, value, sizeof(new_sw->name)-1); 03373 if (data) 03374 strncpy(new_sw->data, data, sizeof(new_sw->data)-1); 03375 else 03376 strncpy(new_sw->data, "", sizeof(new_sw->data)-1); 03377 new_sw->next = NULL; 03378 new_sw->registrar = registrar; 03379 03380 /* ... try to lock this context ... */ 03381 if (ast_mutex_lock(&con->lock)) { 03382 free(new_sw); 03383 errno = EBUSY; 03384 return -1; 03385 } 03386 03387 /* ... go to last sw and check if context is already swd too... */ 03388 i = con->alts; 03389 while (i) { 03390 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) { 03391 free(new_sw); 03392 ast_mutex_unlock(&con->lock); 03393 errno = EEXIST; 03394 return -1; 03395 } 03396 il = i; 03397 i = i->next; 03398 } 03399 03400 /* ... sw new context into context list, unlock, return */ 03401 if (il) 03402 il->next = new_sw; 03403 else 03404 con->alts = new_sw; 03405 if (option_verbose > 2) 03406 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 03407 ast_mutex_unlock(&con->lock); 03408 03409 return 0; 03410 } 03411 03412 /* 03413 * EBUSY - can't lock 03414 * ENOENT - there is not context existence 03415 */ 03416 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar) 03417 { 03418 struct ast_context *c; 03419 03420 if (ast_lock_contexts()) { 03421 errno = EBUSY; 03422 return -1; 03423 } 03424 03425 c = ast_walk_contexts(NULL); 03426 while (c) { 03427 if (!strcmp(ast_get_context_name(c), context)) { 03428 int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar); 03429 ast_unlock_contexts(); 03430 return ret; 03431 } 03432 c = ast_walk_contexts(c); 03433 } 03434 03435 ast_unlock_contexts(); 03436 errno = ENOENT; 03437 return -1; 03438 } 03439 03440 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar) 03441 { 03442 struct ast_ignorepat *ip, *ipl = NULL; 03443 03444 if (ast_mutex_lock(&con->lock)) { 03445 errno = EBUSY; 03446 return -1; 03447 } 03448 03449 ip = con->ignorepats; 03450 while (ip) { 03451 if (!strcmp(ip->pattern, ignorepat) && 03452 (registrar == ip->registrar || !registrar)) { 03453 if (ipl) { 03454 ipl->next = ip->next; 03455 free(ip); 03456 } else { 03457 con->ignorepats = ip->next; 03458 free(ip); 03459 } 03460 ast_mutex_unlock(&con->lock); 03461 return 0; 03462 } 03463 ipl = ip; ip = ip->next; 03464 } 03465 03466 ast_mutex_unlock(&con->lock); 03467 errno = EINVAL; 03468 return -1; 03469 } 03470 03471 /* 03472 * EBUSY - can't lock 03473 * ENOENT - there is no existence of context 03474 */ 03475 int ast_context_add_ignorepat(char *con, char *value, char *registrar) 03476 { 03477 struct ast_context *c; 03478 03479 if (ast_lock_contexts()) { 03480 errno = EBUSY; 03481 return -1; 03482 } 03483 03484 c = ast_walk_contexts(NULL); 03485 while (c) { 03486 if (!strcmp(ast_get_context_name(c), con)) { 03487 int ret = ast_context_add_ignorepat2(c, value, registrar); 03488 ast_unlock_contexts(); 03489 return ret; 03490 } 03491 c = ast_walk_contexts(c); 03492 } 03493 03494 ast_unlock_contexts(); 03495 errno = ENOENT; 03496 return -1; 03497 } 03498 03499 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar) 03500 { 03501 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL; 03502 03503 ignorepat = malloc(sizeof(struct ast_ignorepat)); 03504 if (!ignorepat) { 03505 ast_log(LOG_ERROR, "Out of memory\n"); 03506 errno = ENOMEM; 03507 return -1; 03508 } 03509 memset(ignorepat, 0, sizeof(struct ast_ignorepat)); 03510 strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1); 03511 ignorepat->next = NULL; 03512 ignorepat->registrar = registrar; 03513 ast_mutex_lock(&con->lock); 03514 ignorepatc = con->ignorepats; 03515 while(ignorepatc) { 03516 ignorepatl = ignorepatc; 03517 if (!strcasecmp(ignorepatc->pattern, value)) { 03518 /* Already there */ 03519 ast_mutex_unlock(&con->lock); 03520 errno = EEXIST; 03521 return -1; 03522 } 03523 ignorepatc = ignorepatc->next; 03524 } 03525 if (ignorepatl) 03526 ignorepatl->next = ignorepat; 03527 else 03528 con->ignorepats = ignorepat; 03529 ast_mutex_unlock(&con->lock); 03530 return 0; 03531 03532 } 03533 03534 int ast_ignore_pattern(char *context, char *pattern) 03535 { 03536 struct ast_context *con; 03537 struct ast_ignorepat *pat; 03538 03539 con = ast_context_find(context); 03540 if (con) { 03541 pat = con->ignorepats; 03542 while (pat) { 03543 if (ast_extension_match(pat->pattern, pattern)) 03544 return 1; 03545 pat = pat->next; 03546 } 03547 } 03548 return 0; 03549 } 03550 03551 /* 03552 * EBUSY - can't lock 03553 * ENOENT - no existence of context 03554 * 03555 */ 03556 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid, 03557 char *application, void *data, void (*datad)(void *), char *registrar) 03558 { 03559 struct ast_context *c; 03560 03561 if (ast_lock_contexts()) { 03562 errno = EBUSY; 03563 return -1; 03564 } 03565 03566 c = ast_walk_contexts(NULL); 03567 while (c) { 03568 if (!strcmp(context, ast_get_context_name(c))) { 03569 int ret = ast_add_extension2(c, replace, extension, priority, callerid, 03570 application, data, datad, registrar); 03571 ast_unlock_contexts(); 03572 return ret; 03573 } 03574 c = ast_walk_contexts(c); 03575 } 03576 03577 ast_unlock_contexts(); 03578 errno = ENOENT; 03579 return -1; 03580 } 03581 03582 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority) 03583 { 03584 int res = 0; 03585 ast_mutex_lock(&chan->lock); 03586 03587 if (chan->pbx) { 03588 /* This channel is currently in the PBX */ 03589 if (context && !ast_strlen_zero(context)) 03590 strncpy(chan->context, context, sizeof(chan->context) - 1); 03591 if (exten && !ast_strlen_zero(exten)) 03592 strncpy(chan->exten, exten, sizeof(chan->context) - 1); 03593 if (priority) 03594 chan->priority = priority - 1; 03595 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO); 03596 } else { 03597 /* In order to do it when the channel doesn't really exist within 03598 the PBX, we have to make a new channel, masquerade, and start the PBX 03599 at the new location */ 03600 struct ast_channel *tmpchan; 03601 tmpchan = ast_channel_alloc(0); 03602 if (tmpchan) { 03603 snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name); 03604 ast_setstate(tmpchan, chan->_state); 03605 /* Make formats okay */ 03606 tmpchan->readformat = chan->readformat; 03607 tmpchan->writeformat = chan->writeformat; 03608 /* Setup proper location */ 03609 if (context && !ast_strlen_zero(context)) 03610 strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1); 03611 else 03612 strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1); 03613 if (exten && !ast_strlen_zero(exten)) 03614 strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1); 03615 else 03616 strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1); 03617 if (priority) 03618 tmpchan->priority = priority; 03619 else 03620 tmpchan->priority = chan->priority; 03621 03622 /* Masquerade into temp channel */ 03623 ast_channel_masquerade(tmpchan, chan); 03624 03625 /* Grab the locks and get going */ 03626 ast_mutex_lock(&tmpchan->lock); 03627 ast_do_masquerade(tmpchan); 03628 ast_mutex_unlock(&tmpchan->lock); 03629 /* Start the PBX going on our stolen channel */ 03630 if (ast_pbx_start(tmpchan)) { 03631 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name); 03632 ast_hangup(tmpchan); 03633 res = -1; 03634 } 03635 } else { 03636 res = -1; 03637 } 03638 } 03639 ast_mutex_unlock(&chan->lock); 03640 return res; 03641 } 03642 03643 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority) 03644 { 03645 struct ast_channel *chan; 03646 int res = -1; 03647 03648 chan = ast_channel_walk_locked(NULL); 03649 while(chan) { 03650 if (!strcasecmp(channame, chan->name)) 03651 break; 03652 ast_mutex_unlock(&chan->lock); 03653 chan = ast_channel_walk_locked(chan); 03654 } 03655 03656 if (chan) { 03657 res = ast_async_goto(chan, context, exten, priority); 03658 ast_mutex_unlock(&chan->lock); 03659 } 03660 return res; 03661 } 03662 03663 static void ext_strncpy(char *dst, char *src, int len) 03664 { 03665 int count=0; 03666 03667 while(*src && (count < len - 1)) { 03668 switch(*src) { 03669 case ' ': 03670 /* otherwise exten => [a-b],1,... doesn't work */ 03671 /* case '-': */ 03672 /* Ignore */ 03673 break; 03674 default: 03675 *dst = *src; 03676 dst++; 03677 } 03678 src++; 03679 count++; 03680 } 03681 *dst = '\0'; 03682 } 03683 03684 /* 03685 * EBUSY - can't lock 03686 * EEXIST - extension with the same priority exist and no replace is set 03687 * 03688 */ 03689 int ast_add_extension2(struct ast_context *con, 03690 int replace, char *extension, int priority, char *callerid, 03691 char *application, void *data, void (*datad)(void *), 03692 char *registrar) 03693 { 03694 03695 #define LOG do { if (option_debug) {\ 03696 if (tmp->matchcid) { \ 03697 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \ 03698 } else { \ 03699 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \ 03700 } \ 03701 } else if (option_verbose > 2) { \ 03702 if (tmp->matchcid) { \ 03703 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \ 03704 } else { \ 03705 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \ 03706 } \ 03707 } } while(0) 03708 03709 /* 03710 * This is a fairly complex routine. Different extensions are kept 03711 * in order by the extension number. Then, extensions of different 03712 * priorities (same extension) are kept in a list, according to the 03713 * peer pointer. 03714 */ 03715 struct ast_exten *tmp, *e, *el = NULL, *ep = NULL; 03716 int res; 03717 03718 /* Be optimistic: Build the extension structure first */ 03719 tmp = malloc(sizeof(struct ast_exten)); 03720 if (tmp) { 03721 memset(tmp, 0, sizeof(struct ast_exten)); 03722 ext_strncpy(tmp->exten, extension, sizeof(tmp->exten)); 03723 tmp->priority = priority; 03724 if (callerid) { 03725 ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch)); 03726 tmp->matchcid = 1; 03727 } else { 03728 tmp->cidmatch[0] = '\0'; 03729 tmp->matchcid = 0; 03730 } 03731 strncpy(tmp->app, application, sizeof(tmp->app)-1); 03732 tmp->parent = con; 03733 tmp->data = data; 03734 tmp->datad = datad; 03735 tmp->registrar = registrar; 03736 tmp->peer = NULL; 03737 tmp->next = NULL; 03738 } else { 03739 ast_log(LOG_ERROR, "Out of memory\n"); 03740 errno = ENOMEM; 03741 return -1; 03742 } 03743 if (ast_mutex_lock(&con->lock)) { 03744 free(tmp); 03745 /* And properly destroy the data */ 03746 datad(data); 03747 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name); 03748 errno = EBUSY; 03749 return -1; 03750 } 03751 e = con->root; 03752 while(e) { 03753 res= strcmp(e->exten, extension); 03754 if (!res) { 03755 if (!e->matchcid && !tmp->matchcid) 03756 res = 0; 03757 else if (tmp->matchcid && !e->matchcid) 03758 res = 1; 03759 else if (e->matchcid && !tmp->matchcid) 03760 res = -1; 03761 else 03762 res = strcasecmp(e->cidmatch, tmp->cidmatch); 03763 } 03764 if (res == 0) { 03765 /* We have an exact match, now we find where we are 03766 and be sure there's no duplicates */ 03767 while(e) { 03768 if (e->priority == tmp->priority) { 03769 /* Can't have something exactly the same. Is this a 03770 replacement? If so, replace, otherwise, bonk. */ 03771 if (replace) { 03772 if (ep) { 03773 /* We're in the peer list, insert ourselves */ 03774 ep->peer = tmp; 03775 tmp->peer = e->peer; 03776 } else if (el) { 03777 /* We're the first extension. Take over e's functions */ 03778 el->next = tmp; 03779 tmp->next = e->next; 03780 tmp->peer = e->peer; 03781 } else { 03782 /* We're the very first extension. */ 03783 con->root = tmp; 03784 tmp->next = e->next; 03785 tmp->peer = e->peer; 03786 } 03787 if (tmp->priority == PRIORITY_HINT) 03788 ast_change_hint(e,tmp); 03789 /* Destroy the old one */ 03790 e->datad(e->data); 03791 free(e); 03792 ast_mutex_unlock(&con->lock); 03793 if (tmp->priority == PRIORITY_HINT) 03794 ast_change_hint(e, tmp); 03795 /* And immediately return success. */ 03796 LOG; 03797 return 0; 03798 } else { 03799 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name); 03800 tmp->datad(tmp->data); 03801 free(tmp); 03802 ast_mutex_unlock(&con->lock); 03803 errno = EEXIST; 03804 return -1; 03805 } 03806 } else if (e->priority > tmp->priority) { 03807 /* Slip ourselves in just before e */ 03808 if (ep) { 03809 /* Easy enough, we're just in the peer list */ 03810 ep->peer = tmp; 03811 tmp->peer = e; 03812 } else if (el) { 03813 /* We're the first extension in this peer list */ 03814 el->next = tmp; 03815 tmp->next = e->next; 03816 e->next = NULL; 03817 tmp->peer = e; 03818 } else { 03819 /* We're the very first extension altogether */ 03820 tmp->next = con->root->next; 03821 /* Con->root must always exist or we couldn't get here */ 03822 tmp->peer = con->root; 03823 con->root = tmp; 03824 } 03825 ast_mutex_unlock(&con->lock); 03826 /* And immediately return success. */ 03827 if (tmp->priority == PRIORITY_HINT) 03828 ast_add_hint(tmp); 03829 03830 LOG; 03831 return 0; 03832 } 03833 ep = e; 03834 e = e->peer; 03835 } 03836 /* If we make it here, then it's time for us to go at the very end. 03837 ep *must* be defined or we couldn't have gotten here. */ 03838 ep->peer = tmp; 03839 ast_mutex_unlock(&con->lock); 03840 if (tmp->priority == PRIORITY_HINT) 03841 ast_add_hint(tmp); 03842 03843 /* And immediately return success. */ 03844 LOG; 03845 return 0; 03846 03847 } else if (res > 0) { 03848 /* Insert ourselves just before 'e'. We're the first extension of 03849 this kind */ 03850 tmp->next = e; 03851 if (el) { 03852 /* We're in the list somewhere */ 03853 el->next = tmp; 03854 } else { 03855 /* We're at the top of the list */ 03856 con->root = tmp; 03857 } 03858 ast_mutex_unlock(&con->lock); 03859 if (tmp->priority == PRIORITY_HINT) 03860 ast_add_hint(tmp); 03861 03862 /* And immediately return success. */ 03863 LOG; 03864 return 0; 03865 } 03866 03867 el = e; 03868 e = e->next; 03869 } 03870 /* If we fall all the way through to here, then we need to be on the end. */ 03871 if (el) 03872 el->next = tmp; 03873 else 03874 con->root = tmp; 03875 ast_mutex_unlock(&con->lock); 03876 if (tmp->priority == PRIORITY_HINT) 03877 ast_add_hint(tmp); 03878 LOG; 03879 return 0; 03880 } 03881 03882 struct async_stat { 03883 pthread_t p; 03884 struct ast_channel *chan; 03885 char context[AST_MAX_EXTENSION]; 03886 char exten[AST_MAX_EXTENSION]; 03887 int priority; 03888 int timeout; 03889 char app[AST_MAX_EXTENSION]; 03890 char appdata[1024]; 03891 }; 03892 03893 static void *async_wait(void *data) 03894 { 03895 struct async_stat *as = data; 03896 struct ast_channel *chan = as->chan; 03897 int timeout = as->timeout; 03898 int res; 03899 struct ast_frame *f; 03900 struct ast_app *app; 03901 03902 while(timeout && (chan->_state != AST_STATE_UP)) { 03903 res = ast_waitfor(chan, timeout); 03904 if (res < 1) 03905 break; 03906 if (timeout > -1) 03907 timeout = res; 03908 f = ast_read(chan); 03909 if (!f) 03910 break; 03911 if (f->frametype == AST_FRAME_CONTROL) { 03912 if ((f->subclass == AST_CONTROL_BUSY) || 03913 (f->subclass == AST_CONTROL_CONGESTION) ) 03914 break; 03915 } 03916 ast_frfree(f); 03917 } 03918 if (chan->_state == AST_STATE_UP) { 03919 if (!ast_strlen_zero(as->app)) { 03920 app = pbx_findapp(as->app); 03921 if (app) { 03922 if (option_verbose > 2) 03923 ast_verbose(VERBOSE_PREFIX_3 "Lauching %s(%s) on %s\n", as->app, as->appdata, chan->name); 03924 pbx_exec(chan, app, as->appdata, 1); 03925 } else 03926 ast_log(LOG_WARNING, "No such application '%s'\n", as->app); 03927 } else { 03928 if (!ast_strlen_zero(as->context)) 03929 strncpy(chan->context, as->context, sizeof(chan->context) - 1); 03930 if (!ast_strlen_zero(as->exten)) 03931 strncpy(chan->exten, as->exten, sizeof(chan->exten) - 1); 03932 if (as->priority > 0) 03933 chan->priority = as->priority; 03934 /* Run the PBX */ 03935 if (ast_pbx_run(chan)) { 03936 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name); 03937 } else { 03938 /* PBX will have taken care of this */ 03939 chan = NULL; 03940 } 03941 } 03942 03943 } 03944 free(as); 03945 if (chan) 03946 ast_hangup(chan); 03947 return NULL; 03948 } 03949 03950 int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable, char *account) 03951 { 03952 struct ast_channel *chan; 03953 struct async_stat *as; 03954 int res = -1; 03955 char *var, *tmp; 03956 struct outgoing_helper oh; 03957 pthread_attr_t attr; 03958 03959 if (sync) { 03960 LOAD_OH(oh); 03961 chan = __ast_request_and_dial(type, format, data, timeout, reason, callerid, &oh); 03962 if (chan) { 03963 pbx_builtin_setaccount(chan, account); 03964 if (chan->_state == AST_STATE_UP) { 03965 res = 0; 03966 if (option_verbose > 3) 03967 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name); 03968 03969 if (sync > 1) { 03970 if (ast_pbx_run(chan)) { 03971 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name); 03972 ast_hangup(chan); 03973 res = -1; 03974 } 03975 } else { 03976 if (ast_pbx_start(chan)) { 03977 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name); 03978 ast_hangup(chan); 03979 res = -1; 03980 } 03981 } 03982 } else { 03983 if (option_verbose > 3) 03984 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name); 03985 ast_hangup(chan); 03986 } 03987 } 03988 03989 if(res < 0) { /* the call failed for some reason */ 03990 /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */ 03991 /* check if "failed" exists */ 03992 if (ast_exists_extension(chan, context, "failed", 1, NULL)) { 03993 chan = ast_channel_alloc(0); 03994 if (chan) { 03995 strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1); 03996 if (context && !ast_strlen_zero(context)) 03997 strncpy(chan->context, context, sizeof(chan->context) - 1); 03998 strncpy(chan->exten, "failed", sizeof(chan->exten) - 1); 03999 chan->priority = 1; 04000 if (variable) { 04001 tmp = ast_strdupa(variable); 04002 for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) { 04003 pbx_builtin_setvar( chan, var ); 04004 } 04005 } 04006 ast_pbx_run(chan); 04007 } else 04008 ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n"); 04009 } 04010 } 04011 } else { 04012 as = malloc(sizeof(struct async_stat)); 04013 if (!as) 04014 return -1; 04015 memset(as, 0, sizeof(struct async_stat)); 04016 chan = ast_request_and_dial(type, format, data, timeout, reason, callerid); 04017 if (!chan) { 04018 free(as); 04019 return -1; 04020 } 04021 pbx_builtin_setaccount(chan, account); 04022 as->chan = chan; 04023 strncpy(as->context, context, sizeof(as->context) - 1); 04024 strncpy(as->exten, exten, sizeof(as->exten) - 1); 04025 as->priority = priority; 04026 as->timeout = timeout; 04027 if (variable) { 04028 tmp = ast_strdupa(variable); 04029 for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) 04030 pbx_builtin_setvar( chan, var ); 04031 } 04032 pthread_attr_init(&attr); 04033 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 04034 if (pthread_create(&as->p, &attr, async_wait, as)) { 04035 ast_log(LOG_WARNING, "Failed to start async wait\n"); 04036 free(as); 04037 ast_hangup(chan); 04038 return -1; 04039 } 04040 res = 0; 04041 } 04042 return res; 04043 } 04044 04045 struct app_tmp { 04046 char app[256]; 04047 char data[256]; 04048 struct ast_channel *chan; 04049 pthread_t t; 04050 }; 04051 04052 static void *ast_pbx_run_app(void *data) 04053 { 04054 struct app_tmp *tmp = data; 04055 struct ast_app *app; 04056 app = pbx_findapp(tmp->app); 04057 if (app) { 04058 if (option_verbose > 3) 04059 ast_verbose(VERBOSE_PREFIX_4 "Lauching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name); 04060 pbx_exec(tmp->chan, app, tmp->data, 1); 04061 } else 04062 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app); 04063 ast_hangup(tmp->chan); 04064 free(tmp); 04065 return NULL; 04066 } 04067 04068 int ast_pbx_outgoing_app(char *type, int format, void *data, int timeout, char *app, char *appdata, int *reason, int sync, char *callerid, char *variable, char *account) 04069 { 04070 struct ast_channel *chan; 04071 struct async_stat *as; 04072 struct app_tmp *tmp; 04073 char *var, *vartmp; 04074 int res = -1; 04075 pthread_attr_t attr; 04076 04077 if (!app || ast_strlen_zero(app)) 04078 return -1; 04079 if (sync) { 04080 chan = ast_request_and_dial(type, format, data, timeout, reason, callerid); 04081 if (chan) { 04082 pbx_builtin_setaccount(chan, account); 04083 if (variable) { 04084 vartmp = ast_strdupa(variable); 04085 for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) { 04086 pbx_builtin_setvar( chan, var ); 04087 } 04088 } 04089 if (chan->_state == AST_STATE_UP) { 04090 res = 0; 04091 if (option_verbose > 3) 04092 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name); 04093 tmp = malloc(sizeof(struct app_tmp)); 04094 if (tmp) { 04095 memset(tmp, 0, sizeof(struct app_tmp)); 04096 strncpy(tmp->app, app, sizeof(tmp->app) - 1); 04097 strncpy(tmp->data, appdata, sizeof(tmp->data) - 1); 04098 tmp->chan = chan; 04099 if (sync > 1) { 04100 ast_pbx_run_app(tmp); 04101 } else { 04102 pthread_attr_init(&attr); 04103 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 04104 if (pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) { 04105 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno)); 04106 free(tmp); 04107 ast_hangup(chan); 04108 res = -1; 04109 } 04110 } 04111 } else { 04112 ast_log(LOG_ERROR, "Out of memory :(\n"); 04113 res = -1; 04114 } 04115 } else { 04116 if (option_verbose > 3) 04117 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name); 04118 ast_hangup(chan); 04119 } 04120 } 04121 } else { 04122 as = malloc(sizeof(struct async_stat)); 04123 if (!as) 04124 return -1; 04125 memset(as, 0, sizeof(struct async_stat)); 04126 chan = ast_request_and_dial(type, format, data, timeout, reason, callerid); 04127 if (!chan) { 04128 free(as); 04129 return -1; 04130 } 04131 pbx_builtin_setaccount(chan, account); 04132 as->chan = chan; 04133 strncpy(as->app, app, sizeof(as->app) - 1); 04134 if (appdata) 04135 strncpy(as->appdata, appdata, sizeof(as->appdata) - 1); 04136 as->timeout = timeout; 04137 if (variable) { 04138 vartmp = ast_strdupa(variable); 04139 for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) 04140 pbx_builtin_setvar( chan, var ); 04141 } 04142 /* Start a new thread, and get something handling this channel. */ 04143 pthread_attr_init(&attr); 04144 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 04145 if (pthread_create(&as->p, &attr, async_wait, as)) { 04146 ast_log(LOG_WARNING, "Failed to start async wait\n"); 04147 free(as); 04148 ast_hangup(chan); 04149 return -1; 04150 } 04151 res = 0; 04152 } 04153 return res; 04154 } 04155 04156 static void destroy_exten(struct ast_exten *e) 04157 { 04158 if (e->priority == PRIORITY_HINT) 04159 ast_remove_hint(e); 04160 04161 if (e->datad) 04162 e->datad(e->data); 04163 free(e); 04164 } 04165 04166 void __ast_context_destroy(struct ast_context *con, char *registrar) 04167 { 04168 struct ast_context *tmp, *tmpl=NULL; 04169 struct ast_include *tmpi, *tmpil= NULL; 04170 struct ast_sw *sw, *swl= NULL; 04171 struct ast_exten *e, *el, *en; 04172 struct ast_ignorepat *ipi, *ipl = NULL; 04173 04174 ast_mutex_lock(&conlock); 04175 tmp = contexts; 04176 while(tmp) { 04177 if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) && 04178 (!registrar || !strcasecmp(registrar, tmp->registrar))) { 04179 /* Okay, let's lock the structure to be sure nobody else 04180 is searching through it. */ 04181 if (ast_mutex_lock(&tmp->lock)) { 04182 ast_log(LOG_WARNING, "Unable to lock context lock\n"); 04183 return; 04184 } 04185 if (tmpl) 04186 tmpl->next = tmp->next; 04187 else 04188 contexts = tmp->next; 04189 /* Okay, now we're safe to let it go -- in a sense, we were 04190 ready to let it go as soon as we locked it. */ 04191 ast_mutex_unlock(&tmp->lock); 04192 for (tmpi = tmp->includes; tmpi; ) { 04193 /* Free includes */ 04194 tmpil = tmpi; 04195 tmpi = tmpi->next; 04196 free(tmpil); 04197 } 04198 for (ipi = tmp->ignorepats; ipi; ) { 04199 /* Free ignorepats */ 04200 ipl = ipi; 04201 ipi = ipi->next; 04202 free(ipl); 04203 } 04204 for (sw = tmp->alts; sw; ) { 04205 /* Free switches */ 04206 swl = sw; 04207 sw = sw->next; 04208 free(swl); 04209 swl = sw; 04210 } 04211 for (e = tmp->root; e;) { 04212 for (en = e->peer; en;) { 04213 el = en; 04214 en = en->peer; 04215 destroy_exten(el); 04216 } 04217 el = e; 04218 e = e->next; 04219 destroy_exten(el); 04220 } 04221 ast_mutex_destroy(&tmp->lock); 04222 free(tmp); 04223 if (!con) { 04224 /* Might need to get another one -- restart */ 04225 tmp = contexts; 04226 tmpl = NULL; 04227 tmpil = NULL; 04228 continue; 04229 } 04230 ast_mutex_unlock(&conlock); 04231 return; 04232 } 04233 tmpl = tmp; 04234 tmp = tmp->next; 04235 } 04236 ast_mutex_unlock(&conlock); 04237 } 04238 04239 void ast_context_destroy(struct ast_context *con, char *registrar) 04240 { 04241 __ast_context_destroy(con,registrar); 04242 } 04243 04244 static void wait_for_hangup(struct ast_channel *chan, void *data) 04245 { 04246 int res; 04247 struct ast_frame *f; 04248 int waittime; 04249 04250 if (!data || !strlen(data) || (sscanf(data, "%i", &waittime) != 1) || (waittime < 0)) 04251 waittime = -1; 04252 if (waittime > -1) { 04253 ast_safe_sleep(chan, waittime * 1000); 04254 } else do { 04255 res = ast_waitfor(chan, -1); 04256 if (res < 0) 04257 return; 04258 f = ast_read(chan); 04259 if (f) 04260 ast_frfree(f); 04261 } while(f); 04262 } 04263 04264 static int pbx_builtin_progress(struct ast_channel *chan, void *data) 04265 { 04266 ast_indicate(chan, AST_CONTROL_PROGRESS); 04267 return 0; 04268 } 04269 04270 static int pbx_builtin_ringing(struct ast_channel *chan, void *data) 04271 { 04272 ast_indicate(chan, AST_CONTROL_RINGING); 04273 return 0; 04274 } 04275 04276 static int pbx_builtin_busy(struct ast_channel *chan, void *data) 04277 { 04278 ast_indicate(chan, AST_CONTROL_BUSY); 04279 wait_for_hangup(chan, data); 04280 return -1; 04281 } 04282 04283 static int pbx_builtin_congestion(struct ast_channel *chan, void *data) 04284 { 04285 ast_indicate(chan, AST_CONTROL_CONGESTION); 04286 wait_for_hangup(chan, data); 04287 return -1; 04288 } 04289 04290 static int pbx_builtin_answer(struct ast_channel *chan, void *data) 04291 { 04292 return ast_answer(chan); 04293 } 04294 04295 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data) 04296 { 04297 /* Copy the language as specified */ 04298 strncpy(chan->language, (char *)data, sizeof(chan->language)-1); 04299 return 0; 04300 } 04301 04302 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data) 04303 { 04304 /* Reset the CDR as specified */ 04305 if (data) 04306 ast_cdr_reset(chan->cdr, strchr((char *)data, 'w') ? 1 : 0); 04307 else 04308 ast_cdr_reset(chan->cdr, 0); 04309 return 0; 04310 } 04311 04312 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data) 04313 { 04314 /* Copy the account code as specified */ 04315 if (data) 04316 ast_cdr_setaccount(chan, (char *)data); 04317 else 04318 ast_cdr_setaccount(chan, ""); 04319 return 0; 04320 } 04321 04322 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data) 04323 { 04324 /* Copy the AMA Flags as specified */ 04325 if (data) 04326 ast_cdr_setamaflags(chan, (char *)data); 04327 else 04328 ast_cdr_setamaflags(chan, ""); 04329 return 0; 04330 } 04331 04332 static int pbx_builtin_hangup(struct ast_channel *chan, void *data) 04333 { 04334 /* Just return non-zero and it will hang up */ 04335 return -1; 04336 } 04337 04338 static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data) 04339 { 04340 char newexten[AST_MAX_EXTENSION] = ""; 04341 04342 if (!data || !atoi(data)) { 04343 ast_log(LOG_DEBUG, "Ignoring, since number of digits to strip is 0\n"); 04344 return 0; 04345 } 04346 if (strlen(chan->exten) > atoi(data)) { 04347 strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1); 04348 } 04349 strncpy(chan->exten, newexten, sizeof(chan->exten)-1); 04350 return 0; 04351 } 04352 04353 static int pbx_builtin_prefix(struct ast_channel *chan, void *data) 04354 { 04355 char newexten[AST_MAX_EXTENSION] = ""; 04356 04357 if (!data || ast_strlen_zero(data)) { 04358 ast_log(LOG_DEBUG, "Ignoring, since there is no prefix to add\n"); 04359 return 0; 04360 } 04361 snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten); 04362 strncpy(chan->exten, newexten, sizeof(chan->exten)-1); 04363 if (option_verbose > 2) 04364 ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten); 04365 return 0; 04366 } 04367 04368 static int pbx_builtin_suffix(struct ast_channel *chan, void *data) 04369 { 04370 char newexten[AST_MAX_EXTENSION] = ""; 04371 04372 if (!data || ast_strlen_zero(data)) { 04373 ast_log(LOG_DEBUG, "Ignoring, since there is no suffix to add\n"); 04374 return 0; 04375 } 04376 snprintf(newexten, sizeof(newexten), "%s%s", chan->exten, (char *)data); 04377 strncpy(chan->exten, newexten, sizeof(chan->exten)-1); 04378 if (option_verbose > 2) 04379 ast_verbose(VERBOSE_PREFIX_3 "Appended suffix, new extension is %s\n", chan->exten); 04380 return 0; 04381 } 04382 04383 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data) 04384 { 04385 int res=0; 04386 char *s, *ts; 04387 struct ast_include include; 04388 04389 if (!data) { 04390 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n"); 04391 return -1; 04392 } 04393 04394 s = strdup((char *) data); 04395 ts = s; 04396 04397 /* Separate the Goto path */ 04398 strsep(&ts,"?"); 04399 04400 /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */ 04401 build_timing(&include, s); 04402 if (include_valid(&include)) 04403 res = pbx_builtin_goto(chan, (void *)ts); 04404 free(s); 04405 return res; 04406 } 04407 04408 static int pbx_builtin_wait(struct ast_channel *chan, void *data) 04409 { 04410 int ms; 04411 04412 /* Wait for "n" seconds */ 04413 if (data && atof((char *)data)) { 04414 ms = atof((char *)data) * 1000; 04415 return ast_safe_sleep(chan, ms); 04416 } 04417 return 0; 04418 } 04419 04420 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data) 04421 { 04422 int ms; 04423 04424 /* Wait for "n" seconds */ 04425 if (data && atof((char *)data)) { 04426 ms = atof((char *)data) * 1000; 04427 return ast_waitfordigit(chan, ms); 04428 } 04429 return 0; 04430 } 04431 04432 static int pbx_builtin_background(struct ast_channel *chan, void *data) 04433 { 04434 int res; 04435 04436 /* Answer if need be */ 04437 if (chan->_state != AST_STATE_UP) 04438 if (ast_answer(chan)) 04439 return -1; 04440 /* Stop anything playing */ 04441 ast_stopstream(chan); 04442 /* Stream a file */ 04443 res = ast_streamfile(chan, (char *)data, chan->language); 04444 if (!res) { 04445 res = ast_waitstream(chan, AST_DIGIT_ANY); 04446 ast_stopstream(chan); 04447 } 04448 return res; 04449 } 04450 04451 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data) 04452 { 04453 int x = atoi((char *) data); 04454 04455 /* Set the absolute maximum time how long a call can be connected */ 04456 ast_channel_setwhentohangup(chan,x); 04457 if (option_verbose > 2) 04458 ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x); 04459 return 0; 04460 } 04461 04462 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data) 04463 { 04464 /* Set the timeout for how long to wait between digits */ 04465 chan->pbx->rtimeout = atoi((char *)data); 04466 if (option_verbose > 2) 04467 ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout); 04468 return 0; 04469 } 04470 04471 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data) 04472 { 04473 /* Set the timeout for how long to wait between digits */ 04474 chan->pbx->dtimeout = atoi((char *)data); 04475 if (option_verbose > 2) 04476 ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout); 04477 return 0; 04478 } 04479 04480 static int pbx_builtin_goto(struct ast_channel *chan, void *data) 04481 { 04482 char *s; 04483 char *exten, *pri, *context; 04484 char *stringp=NULL; 04485 04486 if (!data || ast_strlen_zero(data)) { 04487 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n"); 04488 return -1; 04489 } 04490 s = ast_strdupa((void *) data); 04491 stringp=s; 04492 context = strsep(&stringp, "|"); 04493 exten = strsep(&stringp, "|"); 04494 if (!exten) { 04495 /* Only a priority in this one */ 04496 pri = context; 04497 exten = NULL; 04498 context = NULL; 04499 } else { 04500 pri = strsep(&stringp, "|"); 04501 if (!pri) { 04502 /* Only an extension and priority in this one */ 04503 pri = exten; 04504 exten = context; 04505 context = NULL; 04506 } 04507 } 04508 if (atoi(pri) < 0) { 04509 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri); 04510 return -1; 04511 } 04512 /* At this point we have a priority and maybe an extension and a context */ 04513 chan->priority = atoi(pri) - 1; 04514 if (exten && strcasecmp(exten, "BYEXTENSION")) 04515 strncpy(chan->exten, exten, sizeof(chan->exten)-1); 04516 if (context) 04517 strncpy(chan->context, context, sizeof(chan->context)-1); 04518 if (option_verbose > 2) 04519 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1); 04520 ast_cdr_update(chan); 04521 return 0; 04522 } 04523 04524 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name) 04525 { 04526 struct ast_var_t *variables; 04527 struct varshead *headp; 04528 04529 if (chan) 04530 headp=&chan->varshead; 04531 else 04532 headp=&globals; 04533 04534 if (name) { 04535 AST_LIST_TRAVERSE(headp,variables,entries) { 04536 if (!strcmp(name, ast_var_name(variables))) 04537 return ast_var_value(variables); 04538 } 04539 if (headp != &globals) { 04540 /* Check global variables if we haven't already */ 04541 headp = &globals; 04542 AST_LIST_TRAVERSE(headp,variables,entries) { 04543 if (!strcmp(name, ast_var_name(variables))) 04544 return ast_var_value(variables); 04545 } 04546 } 04547 } 04548 return NULL; 04549 } 04550 04551 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value) 04552 { 04553 struct ast_var_t *newvariable; 04554 struct varshead *headp; 04555 if (chan) 04556 headp=&chan->varshead; 04557 else 04558 headp=&globals; 04559 04560 AST_LIST_TRAVERSE (headp,newvariable,entries) { 04561 if (strcasecmp(ast_var_name(newvariable),name)==0) { 04562 /* there is already such a variable, delete it */ 04563 AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries); 04564 ast_var_delete(newvariable); 04565 break; 04566 } 04567 } 04568 04569 if (value) { 04570 if ((option_verbose > 1) && (headp == &globals)) 04571 ast_verbose(VERBOSE_PREFIX_3 "Setting global variable '%s' to '%s'\n",name, value); 04572 newvariable=ast_var_assign(name,value); 04573 AST_LIST_INSERT_HEAD(headp,newvariable,entries); 04574 } 04575 } 04576 04577 int pbx_builtin_setvar(struct ast_channel *chan, void *data) 04578 { 04579 char *name; 04580 char *value; 04581 char *stringp=NULL; 04582 04583 if (!data || ast_strlen_zero(data)) { 04584 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n"); 04585 return 0; 04586 } 04587 04588 stringp=data; 04589 name=strsep(&stringp,"="); 04590 value=strsep(&stringp,"\0"); 04591 04592 pbx_builtin_setvar_helper(chan,name,value); 04593 04594 return(0); 04595 } 04596 04597 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data) 04598 { 04599 char *name; 04600 char *value; 04601 char *stringp=NULL; 04602 04603 if (!data || ast_strlen_zero(data)) { 04604 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n"); 04605 return 0; 04606 } 04607 04608 stringp=data; 04609 name=strsep(&stringp,"="); 04610 value=strsep(&stringp,"\0"); 04611 04612 pbx_builtin_setvar_helper(NULL,name,value); 04613 04614 return(0); 04615 } 04616 04617 04618 static int pbx_builtin_noop(struct ast_channel *chan, void *data) 04619 { 04620 return 0; 04621 } 04622 04623 04624 void pbx_builtin_clear_globals(void) 04625 { 04626 struct ast_var_t *vardata; 04627 while (!AST_LIST_EMPTY(&globals)) { 04628 vardata = AST_LIST_FIRST(&globals); 04629 AST_LIST_REMOVE_HEAD(&globals, entries); 04630 ast_var_delete(vardata); 04631 } 04632 } 04633 04634 static int pbx_checkcondition(char *condition) 04635 { 04636 return condition ? atoi(condition) : 0; 04637 } 04638 04639 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data) 04640 { 04641 char *condition,*branch1,*branch2,*branch; 04642 char *s; 04643 int rc; 04644 char *stringp=NULL; 04645 04646 if (!data || ast_strlen_zero(data)) { 04647 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n"); 04648 return 0; 04649 } 04650 04651 s=ast_strdupa(data); 04652 stringp=s; 04653 condition=strsep(&stringp,"?"); 04654 branch1=strsep(&stringp,":"); 04655 branch2=strsep(&stringp,""); 04656 branch = pbx_checkcondition(condition) ? branch1 : branch2; 04657 04658 if ((branch==NULL) || ast_strlen_zero(branch)) { 04659 ast_log(LOG_NOTICE, "Not taking any branch\n"); 04660 return(0); 04661 } 04662 04663 rc=pbx_builtin_goto(chan,branch); 04664 04665 return(rc); 04666 } 04667 04668 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data) 04669 { 04670 int res = 0; 04671 char tmp[256]; 04672 char *number = (char *) NULL; 04673 char *options = (char *) NULL; 04674 04675 04676 if (!data || ast_strlen_zero((char *)data)) { 04677 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n"); 04678 return -1; 04679 } 04680 strncpy(tmp, (char *)data, sizeof(tmp)-1); 04681 number=tmp; 04682 strsep(&number, "|"); 04683 options = strsep(&number, "|"); 04684 if (options) { 04685 if ( strcasecmp(options, "f") && strcasecmp(options,"m") && 04686 strcasecmp(options, "c") && strcasecmp(options, "n") ) { 04687 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n"); 04688 return -1; 04689 } 04690 } 04691 return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options); 04692 } 04693 04694 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data) 04695 { 04696 int res = 0; 04697 04698 if (data) 04699 res = ast_say_digit_str(chan, (char *)data, "", chan->language); 04700 return res; 04701 } 04702 04703 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data) 04704 { 04705 int res = 0; 04706 04707 if (data) 04708 res = ast_say_character_str(chan, (char *)data, "", chan->language); 04709 return res; 04710 } 04711 04712 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data) 04713 { 04714 int res = 0; 04715 04716 if (data) 04717 res = ast_say_phonetic_str(chan, (char *)data, "", chan->language); 04718 return res; 04719 } 04720 04721 int load_pbx(void) 04722 { 04723 int x; 04724 04725 /* Initialize the PBX */ 04726 if (option_verbose) { 04727 ast_verbose( "Asterisk PBX Core Initializing\n"); 04728 ast_verbose( "Registering builtin applications:\n"); 04729 } 04730 AST_LIST_HEAD_INIT(&globals); 04731 ast_cli_register(&show_applications_cli); 04732 ast_cli_register(&show_application_cli); 04733 ast_cli_register(&show_dialplan_cli); 04734 ast_cli_register(&show_switches_cli); 04735 04736 /* Register builtin applications */ 04737 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) { 04738 if (option_verbose) 04739 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name); 04740 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) { 04741 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name); 04742 return -1; 04743 } 04744 } 04745 return 0; 04746 } 04747 04748 /* 04749 * Lock context list functions ... 04750 */ 04751 int ast_lock_contexts() 04752 { 04753 return ast_mutex_lock(&conlock); 04754 } 04755 04756 int ast_unlock_contexts() 04757 { 04758 return ast_mutex_unlock(&conlock); 04759 } 04760 04761 /* 04762 * Lock context ... 04763 */ 04764 int ast_lock_context(struct ast_context *con) 04765 { 04766 return ast_mutex_lock(&con->lock); 04767 } 04768 04769 int ast_unlock_context(struct ast_context *con) 04770 { 04771 return ast_mutex_unlock(&con->lock); 04772 } 04773 04774 /* 04775 * Name functions ... 04776 */ 04777 char *ast_get_context_name(struct ast_context *con) 04778 { 04779 return con ? con->name : NULL; 04780 } 04781 04782 char *ast_get_extension_name(struct ast_exten *exten) 04783 { 04784 return exten ? exten->exten : NULL; 04785 } 04786 04787 char *ast_get_include_name(struct ast_include *inc) 04788 { 04789 return inc ? inc->name : NULL; 04790 } 04791 04792 char *ast_get_ignorepat_name(struct ast_ignorepat *ip) 04793 { 04794 return ip ? ip->pattern : NULL; 04795 } 04796 04797 int ast_get_extension_priority(struct ast_exten *exten) 04798 { 04799 return exten ? exten->priority : -1; 04800 } 04801 04802 /* 04803 * Registrar info functions ... 04804 */ 04805 char *ast_get_context_registrar(struct ast_context *c) 04806 { 04807 return c ? c->registrar : NULL; 04808 } 04809 04810 char *ast_get_extension_registrar(struct ast_exten *e) 04811 { 04812 return e ? e->registrar : NULL; 04813 } 04814 04815 char *ast_get_include_registrar(struct ast_include *i) 04816 { 04817 return i ? i->registrar : NULL; 04818 } 04819 04820 char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip) 04821 { 04822 return ip ? ip->registrar : NULL; 04823 } 04824 04825 char *ast_get_extension_app(struct ast_exten *e) 04826 { 04827 return e ? e->app : NULL; 04828 } 04829 04830 void *ast_get_extension_app_data(struct ast_exten *e) 04831 { 04832 return e ? e->data : NULL; 04833 } 04834 04835 char *ast_get_switch_name(struct ast_sw *sw) 04836 { 04837 return sw ? sw->name : NULL; 04838 } 04839 04840 char *ast_get_switch_data(struct ast_sw *sw) 04841 { 04842 return sw ? sw->data : NULL; 04843 } 04844 04845 char *ast_get_switch_registrar(struct ast_sw *sw) 04846 { 04847 return sw ? sw->registrar : NULL; 04848 } 04849 04850 /* 04851 * Walking functions ... 04852 */ 04853 struct ast_context *ast_walk_contexts(struct ast_context *con) 04854 { 04855 if (!con) 04856 return contexts; 04857 else 04858 return con->next; 04859 } 04860 04861 struct ast_exten *ast_walk_context_extensions(struct ast_context *con, 04862 struct ast_exten *exten) 04863 { 04864 if (!exten) 04865 return con ? con->root : NULL; 04866 else 04867 return exten->next; 04868 } 04869 04870 struct ast_sw *ast_walk_context_switches(struct ast_context *con, 04871 struct ast_sw *sw) 04872 { 04873 if (!sw) 04874 return con ? con->alts : NULL; 04875 else 04876 return sw->next; 04877 } 04878 04879 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten, 04880 struct ast_exten *priority) 04881 { 04882 if (!priority) 04883 return exten; 04884 else 04885 return priority->peer; 04886 } 04887 04888 struct ast_include *ast_walk_context_includes(struct ast_context *con, 04889 struct ast_include *inc) 04890 { 04891 if (!inc) 04892 return con ? con->includes : NULL; 04893 else 04894 return inc->next; 04895 } 04896 04897 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con, 04898 struct ast_ignorepat *ip) 04899 { 04900 if (!ip) 04901 return con ? con->ignorepats : NULL; 04902 else 04903 return ip->next; 04904 } 04905 04906 int ast_context_verify_includes(struct ast_context *con) 04907 { 04908 struct ast_include *inc; 04909 int res = 0; 04910 04911 for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc)) 04912 if (!ast_context_find(inc->rname)) { 04913 res = -1; 04914 ast_log(LOG_WARNING, "Context '%s' tries includes non-existant context '%s'\n", 04915 ast_get_context_name(con), inc->rname); 04916 } 04917 return res; 04918 }

Generated on Tue Aug 17 16:13:53 2004 for Asterisk by doxygen 1.3.8