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