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