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