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