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