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