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