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

pbx.c

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

Generated on Fri Sep 24 21:03:48 2004 for Asterisk by doxygen 1.3.8