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