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

Generated on Sat Jun 12 16:40:59 2004 for Asterisk by doxygen 1.3.7