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