00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <sys/types.h>
00026 #include <string.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <stdio.h>
00030 #include <ctype.h>
00031 #include <errno.h>
00032 #include <time.h>
00033 #include <sys/time.h>
00034
00035 #include "asterisk.h"
00036
00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 19768 $")
00038
00039 #include "asterisk/lock.h"
00040 #include "asterisk/cli.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/options.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/cdr.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/term.h"
00050 #include "asterisk/manager.h"
00051 #include "asterisk/ast_expr.h"
00052 #include "asterisk/linkedlists.h"
00053 #include "asterisk/say.h"
00054 #include "asterisk/utils.h"
00055 #include "asterisk/causes.h"
00056 #include "asterisk/musiconhold.h"
00057 #include "asterisk/app.h"
00058 #include "asterisk/devicestate.h"
00059 #include "asterisk/compat.h"
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 #ifdef LOW_MEMORY
00072 #define EXT_DATA_SIZE 256
00073 #else
00074 #define EXT_DATA_SIZE 8192
00075 #endif
00076
00077 #define SWITCH_DATA_LENGTH 256
00078
00079 #define VAR_BUF_SIZE 4096
00080
00081 #define VAR_NORMAL 1
00082 #define VAR_SOFTTRAN 2
00083 #define VAR_HARDTRAN 3
00084
00085 #define BACKGROUND_SKIP (1 << 0)
00086 #define BACKGROUND_NOANSWER (1 << 1)
00087 #define BACKGROUND_MATCHEXTEN (1 << 2)
00088 #define BACKGROUND_PLAYBACK (1 << 3)
00089
00090 AST_APP_OPTIONS(background_opts, {
00091 AST_APP_OPTION('s', BACKGROUND_SKIP),
00092 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
00093 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
00094 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
00095 });
00096
00097 #define WAITEXTEN_MOH (1 << 0)
00098
00099 AST_APP_OPTIONS(waitexten_opts, {
00100 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
00101 });
00102
00103 struct ast_context;
00104
00105
00106
00107
00108
00109
00110 struct ast_exten {
00111 char *exten;
00112 int matchcid;
00113 char *cidmatch;
00114 int priority;
00115 char *label;
00116 struct ast_context *parent;
00117 char *app;
00118 void *data;
00119 void (*datad)(void *);
00120 struct ast_exten *peer;
00121 const char *registrar;
00122 struct ast_exten *next;
00123 char stuff[0];
00124 };
00125
00126
00127 struct ast_include {
00128 char *name;
00129 char *rname;
00130 const char *registrar;
00131 int hastime;
00132 struct ast_timing timing;
00133 struct ast_include *next;
00134 char stuff[0];
00135 };
00136
00137
00138 struct ast_sw {
00139 char *name;
00140 const char *registrar;
00141 char *data;
00142 int eval;
00143 struct ast_sw *next;
00144 char *tmpdata;
00145 char stuff[0];
00146 };
00147
00148
00149 struct ast_ignorepat {
00150 const char *registrar;
00151 struct ast_ignorepat *next;
00152 char pattern[0];
00153 };
00154
00155
00156 struct ast_context {
00157 ast_mutex_t lock;
00158 struct ast_exten *root;
00159 struct ast_context *next;
00160 struct ast_include *includes;
00161 struct ast_ignorepat *ignorepats;
00162 const char *registrar;
00163 struct ast_sw *alts;
00164 char name[0];
00165 };
00166
00167
00168
00169 struct ast_app {
00170 int (*execute)(struct ast_channel *chan, void *data);
00171 const char *synopsis;
00172 const char *description;
00173 struct ast_app *next;
00174 char name[0];
00175 };
00176
00177
00178 struct ast_state_cb {
00179 int id;
00180 void *data;
00181 ast_state_cb_type callback;
00182 struct ast_state_cb *next;
00183 };
00184
00185
00186
00187
00188
00189 struct ast_hint {
00190 struct ast_exten *exten;
00191 int laststate;
00192 struct ast_state_cb *callbacks;
00193 struct ast_hint *next;
00194 };
00195
00196 int ast_pbx_outgoing_cdr_failed(void);
00197
00198 static int pbx_builtin_answer(struct ast_channel *, void *);
00199 static int pbx_builtin_goto(struct ast_channel *, void *);
00200 static int pbx_builtin_hangup(struct ast_channel *, void *);
00201 static int pbx_builtin_background(struct ast_channel *, void *);
00202 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
00203 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
00204 static int pbx_builtin_atimeout(struct ast_channel *, void *);
00205 static int pbx_builtin_wait(struct ast_channel *, void *);
00206 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00207 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
00208 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00209 static int pbx_builtin_setaccount(struct ast_channel *, void *);
00210 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00211 static int pbx_builtin_ringing(struct ast_channel *, void *);
00212 static int pbx_builtin_progress(struct ast_channel *, void *);
00213 static int pbx_builtin_congestion(struct ast_channel *, void *);
00214 static int pbx_builtin_busy(struct ast_channel *, void *);
00215 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
00216 static int pbx_builtin_noop(struct ast_channel *, void *);
00217 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00218 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00219 static int pbx_builtin_execiftime(struct ast_channel *, void *);
00220 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00221 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00222 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00223 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00224 static int pbx_builtin_setvar_old(struct ast_channel *, void *);
00225 int pbx_builtin_setvar(struct ast_channel *, void *);
00226 static int pbx_builtin_importvar(struct ast_channel *, void *);
00227
00228 AST_MUTEX_DEFINE_STATIC(globalslock);
00229 static struct varshead globals;
00230
00231 static int autofallthrough = 0;
00232
00233 AST_MUTEX_DEFINE_STATIC(maxcalllock);
00234 static int countcalls = 0;
00235
00236 AST_MUTEX_DEFINE_STATIC(acflock);
00237 static struct ast_custom_function *acf_root = NULL;
00238
00239
00240 static struct pbx_builtin {
00241 char name[AST_MAX_APP];
00242 int (*execute)(struct ast_channel *chan, void *data);
00243 char *synopsis;
00244 char *description;
00245 } builtins[] =
00246 {
00247
00248
00249
00250 { "AbsoluteTimeout", pbx_builtin_atimeout,
00251 "Set absolute maximum time of call",
00252 " AbsoluteTimeout(seconds): This application will set the absolute maximum\n"
00253 "amount of time permitted for a call. A setting of 0 disables the timeout.\n"
00254 " AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
00255 },
00256
00257 { "Answer", pbx_builtin_answer,
00258 "Answer a channel if ringing",
00259 " Answer([delay]): If the call has not been answered, this application will\n"
00260 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
00261 "Asterisk will wait this number of milliseconds before answering the call.\n"
00262 },
00263
00264 { "BackGround", pbx_builtin_background,
00265 "Play a file while awaiting extension",
00266 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
00267 "This application will play the given list of files while waiting for an\n"
00268 "extension to be dialed by the calling channel. To continue waiting for digits\n"
00269 "after this application has finished playing files, the WaitExten application\n"
00270 "should be used. The 'langoverride' option explicity specifies which language\n"
00271 "to attempt to use for the requested sound files. If a 'context' is specified,\n"
00272 "this is the dialplan context that this application will use when exiting to a\n"
00273 "dialed extension."
00274 " If one of the requested sound files does not exist, call processing will be\n"
00275 "terminated.\n"
00276 " Options:\n"
00277 " s - causes the playback of the message to be skipped\n"
00278 " if the channel is not in the 'up' state (i.e. it\n"
00279 " hasn't been answered yet.) If this happens, the\n"
00280 " application will return immediately.\n"
00281 " n - don't answer the channel before playing the files\n"
00282 " m - only break if a digit hit matches a one digit\n"
00283 " extension in the destination context\n"
00284 },
00285
00286 { "Busy", pbx_builtin_busy,
00287 "Indicate the Busy condition",
00288 " Busy([timeout]): This application will indicate the busy condition to\n"
00289 "the calling channel. If the optional timeout is specified, the calling channel\n"
00290 "will be hung up after the specified number of seconds. Otherwise, this\n"
00291 "application will wait until the calling channel hangs up.\n"
00292 },
00293
00294 { "Congestion", pbx_builtin_congestion,
00295 "Indicate the Congestion condition",
00296 " Congestion([timeout]): This application will indicate the congenstion\n"
00297 "condition to the calling channel. If the optional timeout is specified, the\n"
00298 "calling channel will be hung up after the specified number of seconds.\n"
00299 "Otherwise, this application will wait until the calling channel hangs up.\n"
00300 },
00301
00302 { "DigitTimeout", pbx_builtin_dtimeout,
00303 "Set maximum timeout between digits",
00304 " DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
00305 "digits when the user is typing in an extension. When this timeout expires,\n"
00306 "after the user has started to type in an extension, the extension will be\n"
00307 "considered complete, and will be interpreted. Note that if an extension\n"
00308 "typed in is valid, it will not have to timeout to be tested, so typically\n"
00309 "at the expiry of this timeout, the extension will be considered invalid\n"
00310 "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
00311 "exist the call would be terminated). The default timeout is 5 seconds.\n"
00312 " DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout)\n"
00313 },
00314
00315 { "Goto", pbx_builtin_goto,
00316 "Jump to a particular priority, extension, or context",
00317 " Goto([[context|]extension|]priority): This application will cause the\n"
00318 "calling channel to continue dialplan execution at the specified priority.\n"
00319 "If no specific extension, or extension and context, are specified, then this\n"
00320 "application will jump to the specified priority of the current extension.\n"
00321 " If the attempt to jump to another location in the dialplan is not successful,\n"
00322 "then the channel will continue at the next priority of the current extension.\n"
00323 },
00324
00325 { "GotoIf", pbx_builtin_gotoif,
00326 "Conditional goto",
00327 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
00328 "the calling channel to jump to the specified location in the dialplan based on\n"
00329 "the evaluation of the given condition. The channel will continue at\n"
00330 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
00331 "false. The labels are specified with the same syntax as used within the Goto\n"
00332 "application. If the label chosen by the condition is omitted, no jump is\n"
00333 "performed, but execution continues with the next priority in the dialplan.\n"
00334 },
00335
00336 { "GotoIfTime", pbx_builtin_gotoiftime,
00337 "Conditional Goto based on the current time",
00338 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
00339 "This application will have the calling channel jump to the speicified location\n"
00340 "int the dialplan if the current time matches the given time specification.\n"
00341 "Further information on the time specification can be found in examples\n"
00342 "illustrating how to do time-based context includes in the dialplan.\n"
00343 },
00344
00345 { "ExecIfTime", pbx_builtin_execiftime,
00346 "Conditional application execution based on the current time",
00347 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
00348 "This application will execute the specified dialplan application, with optional\n"
00349 "arguments, if the current time matches the given time specification. Further\n"
00350 "information on the time speicification can be found in examples illustrating\n"
00351 "how to do time-based context includes in the dialplan.\n"
00352 },
00353
00354 { "Hangup", pbx_builtin_hangup,
00355 "Hang up the calling channel",
00356 " Hangup(): This application will hang up the calling channel.\n"
00357 },
00358
00359 { "NoOp", pbx_builtin_noop,
00360 "Do Nothing",
00361 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
00362 "purposes. Any text that is provided as arguments to this application can be\n"
00363 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
00364 "variables or functions without having any effect."
00365 },
00366
00367 { "Progress", pbx_builtin_progress,
00368 "Indicate progress",
00369 " Progress(): This application will request that in-band progress information\n"
00370 "be provided to the calling channel.\n"
00371 },
00372
00373 { "ResetCDR", pbx_builtin_resetcdr,
00374 "Resets the Call Data Record",
00375 " ResetCDR([options]): This application causes the Call Data Record to be\n"
00376 "reset.\n"
00377 " Options:\n"
00378 " w -- Store the current CDR record before resetting it.\n"
00379 " a -- Store any stacked records.\n"
00380 " v -- Save CDR variables.\n"
00381 },
00382
00383 { "ResponseTimeout", pbx_builtin_rtimeout,
00384 "Set maximum timeout awaiting response",
00385 " ResponseTimeout(seconds): This will set the maximum amount of time permitted\n"
00386 "to wait for an extension to dialed (see the WaitExten application), before the\n"
00387 "timeout occurs. If this timeout is reached, dialplan execution will continue at\n"
00388 "the 't' extension, if it exists.\n"
00389 " ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout)\n"
00390 },
00391
00392 { "Ringing", pbx_builtin_ringing,
00393 "Indicate ringing tone",
00394 " Ringing(): This application will request that the channel indicate a ringing\n"
00395 "tone to the user.\n"
00396 },
00397
00398 { "SayNumber", pbx_builtin_saynumber,
00399 "Say Number",
00400 " SayNumber(digits[,gender]): This application will play the sounds that\n"
00401 "correspond to the given number. Optionally, a gender may be specified.\n"
00402 "This will use the language that is currently set for the channel. See the\n"
00403 "LANGUAGE function for more information on setting the language for the channel.\n"
00404 },
00405
00406 { "SayDigits", pbx_builtin_saydigits,
00407 "Say Digits",
00408 " SayDigits(digits): This application will play the sounds that correspond\n"
00409 "to the digits of the given number. This will use the language that is currently\n"
00410 "set for the channel. See the LANGUAGE function for more information on setting\n"
00411 "the language for the channel.\n"
00412 },
00413
00414 { "SayAlpha", pbx_builtin_saycharacters,
00415 "Say Alpha",
00416 " SayAlpha(string): This application will play the sounds that correspond to\n"
00417 "the letters of the given string.\n"
00418 },
00419
00420 { "SayPhonetic", pbx_builtin_sayphonetic,
00421 "Say Phonetic",
00422 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
00423 "alphabet that correspond to the letters in the given string.\n"
00424 },
00425
00426 { "SetAccount", pbx_builtin_setaccount,
00427 "Set the CDR Account Code",
00428 " SetAccount([account]): This application will set the channel account code for\n"
00429 "billing purposes.\n"
00430 " SetAccount has been deprecated in favor of the Set(CDR(accountcode)=account).\n"
00431 },
00432
00433 { "SetAMAFlags", pbx_builtin_setamaflags,
00434 "Set the AMA Flags",
00435 " SetAMAFlags([flag]): This channel will set the channel's AMA Flags for billing\n"
00436 "purposes.\n"
00437 },
00438
00439 { "SetGlobalVar", pbx_builtin_setglobalvar,
00440 "Set a global variable to a given value",
00441 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
00442 "the specified value.\n"
00443 },
00444
00445 { "SetLanguage", pbx_builtin_setlanguage,
00446 "Set the channel's preferred language",
00447 " SetLanguage(language): This will set the channel language to the given value.\n"
00448 "This information is used for the syntax in generation of numbers, and to choose\n"
00449 "a sound file in the given language, when it is available.\n"
00450 " For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
00451 "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
00452 "it will play that file. If not, it will play the normal 'demo-congrats'.\n"
00453 "For some language codes, SetLanguage also changes the syntax of some\n"
00454 "Asterisk functions, like SayNumber.\n"
00455 " SetLanguage has been deprecated in favor of Set(LANGUAGE()=language)\n"
00456 },
00457
00458 { "Set", pbx_builtin_setvar,
00459 "Set channel variable(s) or function value(s)",
00460 " Set(name1=value1|name2=value2|..[|options])\n"
00461 "This function can be used to set the value of channel variables or dialplan\n"
00462 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
00463 "if the variable name is prefixed with _, the variable will be inherited into\n"
00464 "channels created from the current channel. If the variable name is prefixed\n"
00465 "with __, the variable will be inherited into channels created from the current\n"
00466 "channel and all children channels.\n"
00467 " Options:\n"
00468 " g - Set variable globally instead of on the channel\n"
00469 " (applies only to variables, not functions)\n"
00470 },
00471
00472 { "SetVar", pbx_builtin_setvar_old,
00473 "Set channel variable(s)",
00474 " SetVar(name1=value1|name2=value2|..[|options]): This application has been\n"
00475 "deprecated in favor of using the Set application.\n"
00476 },
00477
00478 { "ImportVar", pbx_builtin_importvar,
00479 "Import a variable from a channel into a new variable",
00480 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
00481 "from the specified channel (as opposed to the current one) and stores it as\n"
00482 "a variable in the current channel (the channel that is calling this\n"
00483 "application). Variables created by this application have the same inheritance\n"
00484 "properties as those created with the Set application. See the documentation for\n"
00485 "Set for more information.\n"
00486 },
00487
00488 { "Wait", pbx_builtin_wait,
00489 "Waits for some time",
00490 " Wait(seconds): This application waits for a specified number of seconds.\n"
00491 "Then, dialplan execution will continue at the next priority.\n"
00492 " Note that the seconds can be passed with fractions of a second. For example,\n"
00493 "'1.5' will ask the application to wait for 1.5 seconds.\n"
00494 },
00495
00496 { "WaitExten", pbx_builtin_waitexten,
00497 "Waits for an extension to be entered",
00498 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
00499 "a new extension for a specified number of seconds.\n"
00500 " Note that the seconds can be passed with fractions of a second. For example,\n"
00501 "'1.5' will ask the application to wait for 1.5 seconds.\n"
00502 " Options:\n"
00503 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
00504 " Optionally, specify the class for music on hold within parenthesis.\n"
00505 },
00506
00507 };
00508
00509 static struct ast_context *contexts = NULL;
00510 AST_MUTEX_DEFINE_STATIC(conlock);
00511 static struct ast_app *apps = NULL;
00512 AST_MUTEX_DEFINE_STATIC(applock);
00513
00514 struct ast_switch *switches = NULL;
00515 AST_MUTEX_DEFINE_STATIC(switchlock);
00516
00517
00518
00519
00520
00521
00522
00523 AST_MUTEX_DEFINE_STATIC(hintlock);
00524 static int stateid = 1;
00525 struct ast_hint *hints = NULL;
00526 struct ast_state_cb *statecbs = NULL;
00527
00528
00529
00530
00531 int pbx_exec(struct ast_channel *c,
00532 struct ast_app *app,
00533 void *data,
00534 int newstack)
00535 {
00536 int res;
00537
00538 char *saved_c_appl;
00539 char *saved_c_data;
00540
00541 int (*execute)(struct ast_channel *chan, void *data) = app->execute;
00542
00543 if (newstack) {
00544 if (c->cdr)
00545 ast_cdr_setapp(c->cdr, app->name, data);
00546
00547
00548 saved_c_appl= c->appl;
00549 saved_c_data= c->data;
00550
00551 c->appl = app->name;
00552 c->data = data;
00553 res = execute(c, data);
00554
00555 c->appl= saved_c_appl;
00556 c->data= saved_c_data;
00557 return res;
00558 } else
00559 ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
00560 return -1;
00561 }
00562
00563
00564
00565 #define AST_PBX_MAX_STACK 128
00566
00567 #define HELPER_EXISTS 0
00568 #define HELPER_SPAWN 1
00569 #define HELPER_EXEC 2
00570 #define HELPER_CANMATCH 3
00571 #define HELPER_MATCHMORE 4
00572 #define HELPER_FINDLABEL 5
00573
00574
00575
00576 struct ast_app *pbx_findapp(const char *app)
00577 {
00578 struct ast_app *tmp;
00579
00580 if (ast_mutex_lock(&applock)) {
00581 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
00582 return NULL;
00583 }
00584 tmp = apps;
00585 while(tmp) {
00586 if (!strcasecmp(tmp->name, app))
00587 break;
00588 tmp = tmp->next;
00589 }
00590 ast_mutex_unlock(&applock);
00591 return tmp;
00592 }
00593
00594 static struct ast_switch *pbx_findswitch(const char *sw)
00595 {
00596 struct ast_switch *asw;
00597
00598 if (ast_mutex_lock(&switchlock)) {
00599 ast_log(LOG_WARNING, "Unable to obtain application lock\n");
00600 return NULL;
00601 }
00602 asw = switches;
00603 while(asw) {
00604 if (!strcasecmp(asw->name, sw))
00605 break;
00606 asw = asw->next;
00607 }
00608 ast_mutex_unlock(&switchlock);
00609 return asw;
00610 }
00611
00612 static inline int include_valid(struct ast_include *i)
00613 {
00614 if (!i->hastime)
00615 return 1;
00616
00617 return ast_check_timing(&(i->timing));
00618 }
00619
00620 static void pbx_destroy(struct ast_pbx *p)
00621 {
00622 free(p);
00623 }
00624
00625 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
00626 \
00627 if (pattern[0] != '_') \
00628 return 0;\
00629 \
00630 match=1;\
00631 pattern++;\
00632 while(match && *data && *pattern && (*pattern != '/')) {\
00633 while (*data == '-' && (*(data+1) != '\0')) data++;\
00634 switch(toupper(*pattern)) {\
00635 case '[': \
00636 {\
00637 int i,border=0;\
00638 char *where;\
00639 match=0;\
00640 pattern++;\
00641 where=strchr(pattern,']');\
00642 if (where)\
00643 border=(int)(where-pattern);\
00644 if (!where || border > strlen(pattern)) {\
00645 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
00646 return match;\
00647 }\
00648 for (i=0; i<border; i++) {\
00649 int res=0;\
00650 if (i+2<border)\
00651 if (pattern[i+1]=='-') {\
00652 if (*data >= pattern[i] && *data <= pattern[i+2]) {\
00653 res=1;\
00654 } else {\
00655 i+=2;\
00656 continue;\
00657 }\
00658 }\
00659 if (res==1 || *data==pattern[i]) {\
00660 match = 1;\
00661 break;\
00662 }\
00663 }\
00664 pattern+=border;\
00665 break;\
00666 }\
00667 case 'N':\
00668 if ((*data < '2') || (*data > '9'))\
00669 match=0;\
00670 break;\
00671 case 'X':\
00672 if ((*data < '0') || (*data > '9'))\
00673 match = 0;\
00674 break;\
00675 case 'Z':\
00676 if ((*data < '1') || (*data > '9'))\
00677 match = 0;\
00678 break;\
00679 case '.':\
00680 \
00681 return 1;\
00682 case '!':\
00683 \
00684 return 2;\
00685 case ' ':\
00686 case '-':\
00687 \
00688 data--;\
00689 break;\
00690 default:\
00691 if (*data != *pattern)\
00692 match =0;\
00693 }\
00694 data++;\
00695 pattern++;\
00696 }\
00697 \
00698 if (match && !*data && (*pattern == '!'))\
00699 return 2;\
00700 }
00701
00702 int ast_extension_match(const char *pattern, const char *data)
00703 {
00704 int match;
00705
00706 if (!strcmp(pattern, data))
00707 return 1;
00708 EXTENSION_MATCH_CORE(data,pattern,match);
00709
00710 if (*data || (*pattern && (*pattern != '/')))
00711 match = 0;
00712 return match;
00713 }
00714
00715 int ast_extension_close(const char *pattern, const char *data, int needmore)
00716 {
00717 int match;
00718
00719
00720 if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
00721 return 0;
00722
00723 if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
00724 (!needmore || (strlen(pattern) > strlen(data)))) {
00725 return 1;
00726 }
00727 EXTENSION_MATCH_CORE(data,pattern,match);
00728
00729
00730 if (!needmore || *pattern || match == 2) {
00731 return match;
00732 } else
00733 return 0;
00734 }
00735
00736 struct ast_context *ast_context_find(const char *name)
00737 {
00738 struct ast_context *tmp;
00739 ast_mutex_lock(&conlock);
00740 if (name) {
00741 tmp = contexts;
00742 while(tmp) {
00743 if (!strcasecmp(name, tmp->name))
00744 break;
00745 tmp = tmp->next;
00746 }
00747 } else
00748 tmp = contexts;
00749 ast_mutex_unlock(&conlock);
00750 return tmp;
00751 }
00752
00753 #define STATUS_NO_CONTEXT 1
00754 #define STATUS_NO_EXTENSION 2
00755 #define STATUS_NO_PRIORITY 3
00756 #define STATUS_NO_LABEL 4
00757 #define STATUS_SUCCESS 5
00758
00759 static int matchcid(const char *cidpattern, const char *callerid)
00760 {
00761 int failresult;
00762
00763
00764
00765
00766 if (!ast_strlen_zero(cidpattern))
00767 failresult = 0;
00768 else
00769 failresult = 1;
00770
00771 if (!callerid)
00772 return failresult;
00773
00774 return ast_extension_match(cidpattern, callerid);
00775 }
00776
00777 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data, const char **foundcontext)
00778 {
00779 int x, res;
00780 struct ast_context *tmp;
00781 struct ast_exten *e, *eroot;
00782 struct ast_include *i;
00783 struct ast_sw *sw;
00784 struct ast_switch *asw;
00785
00786
00787 if (!*stacklen) {
00788 *status = STATUS_NO_CONTEXT;
00789 *swo = NULL;
00790 *data = NULL;
00791 }
00792
00793 if (*stacklen >= AST_PBX_MAX_STACK) {
00794 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
00795 return NULL;
00796 }
00797
00798 for (x=0; x<*stacklen; x++) {
00799 if (!strcasecmp(incstack[x], context))
00800 return NULL;
00801 }
00802 if (bypass)
00803 tmp = bypass;
00804 else
00805 tmp = contexts;
00806 while(tmp) {
00807
00808 if (bypass || !strcmp(tmp->name, context)) {
00809 struct ast_exten *earlymatch = NULL;
00810
00811 if (*status < STATUS_NO_EXTENSION)
00812 *status = STATUS_NO_EXTENSION;
00813 for (eroot = tmp->root; eroot; eroot=eroot->next) {
00814 int match = 0;
00815
00816 if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
00817 ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
00818 ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
00819 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
00820
00821 if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
00822
00823
00824 earlymatch = eroot;
00825 } else {
00826 e = eroot;
00827 if (*status < STATUS_NO_PRIORITY)
00828 *status = STATUS_NO_PRIORITY;
00829 while(e) {
00830
00831 if (action == HELPER_FINDLABEL) {
00832 if (*status < STATUS_NO_LABEL)
00833 *status = STATUS_NO_LABEL;
00834 if (label && e->label && !strcmp(label, e->label)) {
00835 *status = STATUS_SUCCESS;
00836 *foundcontext = context;
00837 return e;
00838 }
00839 } else if (e->priority == priority) {
00840 *status = STATUS_SUCCESS;
00841 *foundcontext = context;
00842 return e;
00843 }
00844 e = e->peer;
00845 }
00846 }
00847 }
00848 }
00849 if (earlymatch) {
00850
00851
00852
00853
00854 return NULL;
00855 }
00856
00857 sw = tmp->alts;
00858 while(sw) {
00859 if ((asw = pbx_findswitch(sw->name))) {
00860
00861 if (sw->eval)
00862 pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
00863 if (action == HELPER_CANMATCH)
00864 res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
00865 else if (action == HELPER_MATCHMORE)
00866 res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
00867 else
00868 res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
00869 if (res) {
00870
00871 *swo = asw;
00872 *data = sw->eval ? sw->tmpdata : sw->data;
00873 *foundcontext = context;
00874 return NULL;
00875 }
00876 } else {
00877 ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
00878 }
00879 sw = sw->next;
00880 }
00881
00882 incstack[*stacklen] = tmp->name;
00883 (*stacklen)++;
00884
00885 i = tmp->includes;
00886 while(i) {
00887 if (include_valid(i)) {
00888 if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
00889 return e;
00890 if (*swo)
00891 return NULL;
00892 }
00893 i = i->next;
00894 }
00895 break;
00896 }
00897 tmp = tmp->next;
00898 }
00899 return NULL;
00900 }
00901
00902
00903 #define DONT_HAVE_LENGTH 0x80000000
00904
00905 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
00906 {
00907 char *varchar, *offsetchar = NULL;
00908 int parens=0;
00909
00910 *offset = 0;
00911 *length = DONT_HAVE_LENGTH;
00912 *isfunc = 0;
00913 for (varchar=var; *varchar; varchar++) {
00914 switch (*varchar) {
00915 case '(':
00916 (*isfunc)++;
00917 parens++;
00918 break;
00919 case ')':
00920 parens--;
00921 break;
00922 case ':':
00923 if (parens == 0) {
00924 offsetchar = varchar + 1;
00925 *varchar = '\0';
00926 goto pvn_endfor;
00927 }
00928 }
00929 }
00930 pvn_endfor:
00931 if (offsetchar) {
00932 sscanf(offsetchar, "%d:%d", offset, length);
00933 return 1;
00934 } else {
00935 return 0;
00936 }
00937 }
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
00948 {
00949 char *ret = workspace;
00950 int lr;
00951
00952 ast_copy_string(workspace, value, workspace_len);
00953
00954 if (offset == 0 && length < 0)
00955 return ret;
00956
00957 lr = strlen(ret);
00958
00959 if (offset < 0) {
00960 offset = lr + offset;
00961 if (offset < 0)
00962 offset = 0;
00963 }
00964
00965
00966 if (offset >= lr)
00967 return ret + lr;
00968
00969 ret += offset;
00970 if (length >= 0 && length < lr - offset)
00971 ret[length] = '\0';
00972
00973 return ret;
00974 }
00975
00976
00977
00978
00979 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
00980 {
00981 char tmpvar[80];
00982 time_t thistime;
00983 struct tm brokentime;
00984 int offset, offset2, isfunc;
00985 struct ast_var_t *variables;
00986
00987 if (c)
00988 headp=&c->varshead;
00989 *ret=NULL;
00990 ast_copy_string(tmpvar, var, sizeof(tmpvar));
00991 if (parse_variable_name(tmpvar, &offset, &offset2, &isfunc)) {
00992 pbx_retrieve_variable(c, tmpvar, ret, workspace, workspacelen, headp);
00993 if (!(*ret))
00994 return;
00995 *ret = substring(*ret, offset, offset2, workspace, workspacelen);
00996 } else if (c && !strncmp(var, "CALL", 4)) {
00997 if (!strncmp(var + 4, "ER", 2)) {
00998 if (!strncmp(var + 6, "ID", 2)) {
00999 if (!var[8]) {
01000 if (c->cid.cid_num) {
01001 if (c->cid.cid_name) {
01002 snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
01003 } else {
01004 ast_copy_string(workspace, c->cid.cid_num, workspacelen);
01005 }
01006 *ret = workspace;
01007 } else if (c->cid.cid_name) {
01008 ast_copy_string(workspace, c->cid.cid_name, workspacelen);
01009 *ret = workspace;
01010 } else
01011 *ret = NULL;
01012 } else if (!strcmp(var + 8, "NUM")) {
01013
01014 if (c->cid.cid_num) {
01015 ast_copy_string(workspace, c->cid.cid_num, workspacelen);
01016 *ret = workspace;
01017 } else
01018 *ret = NULL;
01019 } else if (!strcmp(var + 8, "NAME")) {
01020
01021 if (c->cid.cid_name) {
01022 ast_copy_string(workspace, c->cid.cid_name, workspacelen);
01023 *ret = workspace;
01024 } else
01025 *ret = NULL;
01026 } else
01027 goto icky;
01028 } else if (!strcmp(var + 6, "ANI")) {
01029
01030 if (c->cid.cid_ani) {
01031 ast_copy_string(workspace, c->cid.cid_ani, workspacelen);
01032 *ret = workspace;
01033 } else
01034 *ret = NULL;
01035 } else
01036 goto icky;
01037 } else if (!strncmp(var + 4, "ING", 3)) {
01038 if (!strcmp(var + 7, "PRES")) {
01039
01040 snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
01041 *ret = workspace;
01042 } else if (!strcmp(var + 7, "ANI2")) {
01043
01044 snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
01045 *ret = workspace;
01046 } else if (!strcmp(var + 7, "TON")) {
01047
01048 snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
01049 *ret = workspace;
01050 } else if (!strcmp(var + 7, "TNS")) {
01051
01052 snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
01053 *ret = workspace;
01054 } else
01055 goto icky;
01056 } else
01057 goto icky;
01058 } else if (c && !strcmp(var, "DNID")) {
01059 if (c->cid.cid_dnid) {
01060 ast_copy_string(workspace, c->cid.cid_dnid, workspacelen);
01061 *ret = workspace;
01062 } else
01063 *ret = NULL;
01064 } else if (c && !strcmp(var, "HINT")) {
01065 if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
01066 *ret = NULL;
01067 else
01068 *ret = workspace;
01069 } else if (c && !strcmp(var, "HINTNAME")) {
01070 if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
01071 *ret = NULL;
01072 else
01073 *ret = workspace;
01074 } else if (c && !strcmp(var, "EXTEN")) {
01075 ast_copy_string(workspace, c->exten, workspacelen);
01076 *ret = workspace;
01077 } else if (c && !strcmp(var, "RDNIS")) {
01078 if (c->cid.cid_rdnis) {
01079 ast_copy_string(workspace, c->cid.cid_rdnis, workspacelen);
01080 *ret = workspace;
01081 } else
01082 *ret = NULL;
01083 } else if (c && !strcmp(var, "CONTEXT")) {
01084 ast_copy_string(workspace, c->context, workspacelen);
01085 *ret = workspace;
01086 } else if (c && !strcmp(var, "PRIORITY")) {
01087 snprintf(workspace, workspacelen, "%d", c->priority);
01088 *ret = workspace;
01089 } else if (c && !strcmp(var, "CHANNEL")) {
01090 ast_copy_string(workspace, c->name, workspacelen);
01091 *ret = workspace;
01092 } else if (!strcmp(var, "EPOCH")) {
01093 snprintf(workspace, workspacelen, "%u",(int)time(NULL));
01094 *ret = workspace;
01095 } else if (!strcmp(var, "DATETIME")) {
01096 thistime=time(NULL);
01097 localtime_r(&thistime, &brokentime);
01098 snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
01099 brokentime.tm_mday,
01100 brokentime.tm_mon+1,
01101 brokentime.tm_year+1900,
01102 brokentime.tm_hour,
01103 brokentime.tm_min,
01104 brokentime.tm_sec
01105 );
01106 *ret = workspace;
01107 } else if (!strcmp(var, "TIMESTAMP")) {
01108 thistime=time(NULL);
01109 localtime_r(&thistime, &brokentime);
01110
01111 snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
01112 brokentime.tm_year+1900,
01113 brokentime.tm_mon+1,
01114 brokentime.tm_mday,
01115 brokentime.tm_hour,
01116 brokentime.tm_min,
01117 brokentime.tm_sec
01118 );
01119 *ret = workspace;
01120 } else if (c && !strcmp(var, "UNIQUEID")) {
01121 snprintf(workspace, workspacelen, "%s", c->uniqueid);
01122 *ret = workspace;
01123 } else if (c && !strcmp(var, "HANGUPCAUSE")) {
01124 snprintf(workspace, workspacelen, "%d", c->hangupcause);
01125 *ret = workspace;
01126 } else if (c && !strcmp(var, "ACCOUNTCODE")) {
01127 ast_copy_string(workspace, c->accountcode, workspacelen);
01128 *ret = workspace;
01129 } else if (c && !strcmp(var, "LANGUAGE")) {
01130 ast_copy_string(workspace, c->language, workspacelen);
01131 *ret = workspace;
01132 } else {
01133 icky:
01134 if (headp) {
01135 AST_LIST_TRAVERSE(headp,variables,entries) {
01136 #if 0
01137 ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
01138 #endif
01139 if (strcasecmp(ast_var_name(variables),var)==0) {
01140 *ret=ast_var_value(variables);
01141 if (*ret) {
01142 ast_copy_string(workspace, *ret, workspacelen);
01143 *ret = workspace;
01144 }
01145 break;
01146 }
01147 }
01148 }
01149 if (!(*ret)) {
01150
01151 ast_mutex_lock(&globalslock);
01152 AST_LIST_TRAVERSE(&globals,variables,entries) {
01153 if (strcasecmp(ast_var_name(variables),var)==0) {
01154 *ret = ast_var_value(variables);
01155 if (*ret) {
01156 ast_copy_string(workspace, *ret, workspacelen);
01157 *ret = workspace;
01158 }
01159 }
01160 }
01161 ast_mutex_unlock(&globalslock);
01162 }
01163 }
01164 }
01165
01166
01167
01168
01169 static int handle_show_functions(int fd, int argc, char *argv[])
01170 {
01171 struct ast_custom_function *acf;
01172 int count_acf = 0;
01173
01174 ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
01175 for (acf = acf_root ; acf; acf = acf->next) {
01176 ast_cli(fd, "%-20.20s %-35.35s %s\n", acf->name, acf->syntax, acf->synopsis);
01177 count_acf++;
01178 }
01179 ast_cli(fd, "%d custom functions installed.\n", count_acf);
01180 return 0;
01181 }
01182
01183 static int handle_show_function(int fd, int argc, char *argv[])
01184 {
01185 struct ast_custom_function *acf;
01186
01187 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
01188 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
01189 char stxtitle[40], *syntax = NULL;
01190 int synopsis_size, description_size, syntax_size;
01191
01192 if (argc < 3) return RESULT_SHOWUSAGE;
01193
01194 if (!(acf = ast_custom_function_find(argv[2]))) {
01195 ast_cli(fd, "No function by that name registered.\n");
01196 return RESULT_FAILURE;
01197
01198 }
01199
01200 if (acf->synopsis)
01201 synopsis_size = strlen(acf->synopsis) + 23;
01202 else
01203 synopsis_size = strlen("Not available") + 23;
01204 synopsis = alloca(synopsis_size);
01205
01206 if (acf->desc)
01207 description_size = strlen(acf->desc) + 23;
01208 else
01209 description_size = strlen("Not available") + 23;
01210 description = alloca(description_size);
01211
01212 if (acf->syntax)
01213 syntax_size = strlen(acf->syntax) + 23;
01214 else
01215 syntax_size = strlen("Not available") + 23;
01216 syntax = alloca(syntax_size);
01217
01218 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about function '%s' =- \n\n", acf->name);
01219 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
01220 term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
01221 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
01222 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
01223 term_color(syntax,
01224 acf->syntax ? acf->syntax : "Not available",
01225 COLOR_CYAN, 0, syntax_size);
01226 term_color(synopsis,
01227 acf->synopsis ? acf->synopsis : "Not available",
01228 COLOR_CYAN, 0, synopsis_size);
01229 term_color(description,
01230 acf->desc ? acf->desc : "Not available",
01231 COLOR_CYAN, 0, description_size);
01232
01233 ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
01234
01235 return RESULT_SUCCESS;
01236 }
01237
01238 static char *complete_show_function(char *line, char *word, int pos, int state)
01239 {
01240 struct ast_custom_function *acf;
01241 int which = 0;
01242
01243
01244 if (ast_mutex_lock(&acflock)) {
01245 ast_log(LOG_ERROR, "Unable to lock function list\n");
01246 return NULL;
01247 }
01248
01249 acf = acf_root;
01250 while (acf) {
01251 if (!strncasecmp(word, acf->name, strlen(word))) {
01252 if (++which > state) {
01253 char *ret = strdup(acf->name);
01254 ast_mutex_unlock(&acflock);
01255 return ret;
01256 }
01257 }
01258 acf = acf->next;
01259 }
01260
01261 ast_mutex_unlock(&acflock);
01262 return NULL;
01263 }
01264
01265 struct ast_custom_function* ast_custom_function_find(char *name)
01266 {
01267 struct ast_custom_function *acfptr;
01268
01269
01270 if (ast_mutex_lock(&acflock)) {
01271 ast_log(LOG_ERROR, "Unable to lock function list\n");
01272 return NULL;
01273 }
01274
01275 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
01276 if (!strcmp(name, acfptr->name)) {
01277 break;
01278 }
01279 }
01280
01281 ast_mutex_unlock(&acflock);
01282
01283 return acfptr;
01284 }
01285
01286 int ast_custom_function_unregister(struct ast_custom_function *acf)
01287 {
01288 struct ast_custom_function *acfptr, *lastacf = NULL;
01289 int res = -1;
01290
01291 if (!acf)
01292 return -1;
01293
01294
01295 if (ast_mutex_lock(&acflock)) {
01296 ast_log(LOG_ERROR, "Unable to lock function list\n");
01297 return -1;
01298 }
01299
01300 for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
01301 if (acfptr == acf) {
01302 if (lastacf) {
01303 lastacf->next = acf->next;
01304 } else {
01305 acf_root = acf->next;
01306 }
01307 res = 0;
01308 break;
01309 }
01310 lastacf = acfptr;
01311 }
01312
01313 ast_mutex_unlock(&acflock);
01314
01315 if (!res && (option_verbose > 1))
01316 ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
01317
01318 return res;
01319 }
01320
01321 int ast_custom_function_register(struct ast_custom_function *acf)
01322 {
01323 if (!acf)
01324 return -1;
01325
01326
01327 if (ast_mutex_lock(&acflock)) {
01328 ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
01329 return -1;
01330 }
01331
01332 if (ast_custom_function_find(acf->name)) {
01333 ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
01334 ast_mutex_unlock(&acflock);
01335 return -1;
01336 }
01337
01338 acf->next = acf_root;
01339 acf_root = acf;
01340
01341 ast_mutex_unlock(&acflock);
01342
01343 if (option_verbose > 1)
01344 ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
01345
01346 return 0;
01347 }
01348
01349 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
01350 {
01351 char *args = NULL, *function, *p;
01352 char *ret = "0";
01353 struct ast_custom_function *acfptr;
01354
01355 function = ast_strdupa(in);
01356 if (!function) {
01357 ast_log(LOG_ERROR, "Out of memory\n");
01358 return ret;
01359 }
01360 if ((args = strchr(function, '('))) {
01361 *args = '\0';
01362 args++;
01363 if ((p = strrchr(args, ')'))) {
01364 *p = '\0';
01365 } else {
01366 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
01367 }
01368 } else {
01369 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
01370 }
01371
01372 if ((acfptr = ast_custom_function_find(function))) {
01373
01374 if (acfptr->read) {
01375 return acfptr->read(chan, function, args, workspace, len);
01376 } else {
01377 ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
01378 }
01379 } else {
01380 ast_log(LOG_ERROR, "Function %s not registered\n", function);
01381 }
01382 return ret;
01383 }
01384
01385 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
01386 {
01387 char *args = NULL, *function, *p;
01388 struct ast_custom_function *acfptr;
01389
01390 function = ast_strdupa(in);
01391 if (!function) {
01392 ast_log(LOG_ERROR, "Out of memory\n");
01393 return;
01394 }
01395 if ((args = strchr(function, '('))) {
01396 *args = '\0';
01397 args++;
01398 if ((p = strrchr(args, ')'))) {
01399 *p = '\0';
01400 } else {
01401 ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
01402 }
01403 } else {
01404 ast_log(LOG_WARNING, "Function doesn't contain parentheses. Assuming null argument.\n");
01405 }
01406
01407 if ((acfptr = ast_custom_function_find(function))) {
01408
01409 if (acfptr->write) {
01410 acfptr->write(chan, function, args, value);
01411 } else {
01412 ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
01413 }
01414 } else {
01415 ast_log(LOG_ERROR, "Function %s not registered\n", function);
01416 }
01417 }
01418
01419 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
01420 {
01421 char *cp4;
01422 const char *tmp, *whereweare;
01423 int length, offset, offset2, isfunction;
01424 char *workspace = NULL;
01425 char *ltmp = NULL, *var = NULL;
01426 char *nextvar, *nextexp, *nextthing;
01427 char *vars, *vare;
01428 int pos, brackets, needsub, len;
01429
01430
01431
01432 whereweare=tmp=cp1;
01433 while(!ast_strlen_zero(whereweare) && count) {
01434
01435 pos = strlen(whereweare);
01436 nextvar = NULL;
01437 nextexp = NULL;
01438 nextthing = strchr(whereweare, '$');
01439 if (nextthing) {
01440 switch(nextthing[1]) {
01441 case '{':
01442 nextvar = nextthing;
01443 pos = nextvar - whereweare;
01444 break;
01445 case '[':
01446 nextexp = nextthing;
01447 pos = nextexp - whereweare;
01448 break;
01449 }
01450 }
01451
01452 if (pos) {
01453
01454 if (pos > count)
01455 pos = count;
01456
01457
01458 memcpy(cp2, whereweare, pos);
01459
01460 count -= pos;
01461 cp2 += pos;
01462 whereweare += pos;
01463 }
01464
01465 if (nextvar) {
01466
01467
01468
01469 vars = vare = nextvar + 2;
01470 brackets = 1;
01471 needsub = 0;
01472
01473
01474 while(brackets && *vare) {
01475 if ((vare[0] == '$') && (vare[1] == '{')) {
01476 needsub++;
01477 brackets++;
01478 } else if (vare[0] == '}') {
01479 brackets--;
01480 } else if ((vare[0] == '$') && (vare[1] == '['))
01481 needsub++;
01482 vare++;
01483 }
01484 if (brackets)
01485 ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
01486 len = vare - vars - 1;
01487
01488
01489 whereweare += (len + 3);
01490
01491 if (!var)
01492 var = alloca(VAR_BUF_SIZE);
01493
01494
01495 ast_copy_string(var, vars, len + 1);
01496
01497
01498 if (needsub) {
01499 if (!ltmp)
01500 ltmp = alloca(VAR_BUF_SIZE);
01501
01502 memset(ltmp, 0, VAR_BUF_SIZE);
01503 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
01504 vars = ltmp;
01505 } else {
01506 vars = var;
01507 }
01508
01509 if (!workspace)
01510 workspace = alloca(VAR_BUF_SIZE);
01511
01512 workspace[0] = '\0';
01513
01514 parse_variable_name(vars, &offset, &offset2, &isfunction);
01515 if (isfunction) {
01516
01517 cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE);
01518
01519 ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
01520 } else {
01521
01522 pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
01523 }
01524 if (cp4) {
01525 cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
01526
01527 length = strlen(cp4);
01528 if (length > count)
01529 length = count;
01530 memcpy(cp2, cp4, length);
01531 count -= length;
01532 cp2 += length;
01533 }
01534 } else if (nextexp) {
01535
01536
01537
01538 vars = vare = nextexp + 2;
01539 brackets = 1;
01540 needsub = 0;
01541
01542
01543 while(brackets && *vare) {
01544 if ((vare[0] == '$') && (vare[1] == '[')) {
01545 needsub++;
01546 brackets++;
01547 vare++;
01548 } else if (vare[0] == '[') {
01549 brackets++;
01550 } else if (vare[0] == ']') {
01551 brackets--;
01552 } else if ((vare[0] == '$') && (vare[1] == '{')) {
01553 needsub++;
01554 vare++;
01555 }
01556 vare++;
01557 }
01558 if (brackets)
01559 ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
01560 len = vare - vars - 1;
01561
01562
01563 whereweare += (len + 3);
01564
01565 if (!var)
01566 var = alloca(VAR_BUF_SIZE);
01567
01568
01569 ast_copy_string(var, vars, len + 1);
01570
01571
01572 if (needsub) {
01573 if (!ltmp)
01574 ltmp = alloca(VAR_BUF_SIZE);
01575
01576 memset(ltmp, 0, VAR_BUF_SIZE);
01577 pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
01578 vars = ltmp;
01579 } else {
01580 vars = var;
01581 }
01582
01583 length = ast_expr(vars, cp2, count);
01584
01585 if (length) {
01586 ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
01587 count -= length;
01588 cp2 += length;
01589 }
01590 } else
01591 break;
01592 }
01593 }
01594
01595 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
01596 {
01597 pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
01598 }
01599
01600 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
01601 {
01602 pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
01603 }
01604
01605 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
01606 {
01607 memset(passdata, 0, datalen);
01608
01609
01610 if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
01611 ast_copy_string(passdata, e->data, datalen);
01612 return;
01613 }
01614
01615 pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
01616 }
01617
01618 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
01619 {
01620 struct ast_exten *e;
01621 struct ast_app *app;
01622 struct ast_switch *sw;
01623 char *data;
01624 const char *foundcontext=NULL;
01625 int newstack = 0;
01626 int res;
01627 int status = 0;
01628 char *incstack[AST_PBX_MAX_STACK];
01629 char passdata[EXT_DATA_SIZE];
01630 int stacklen = 0;
01631 char tmp[80];
01632 char tmp2[80];
01633 char tmp3[EXT_DATA_SIZE];
01634 char atmp[80];
01635 char atmp2[EXT_DATA_SIZE+100];
01636
01637 if (ast_mutex_lock(&conlock)) {
01638 ast_log(LOG_WARNING, "Unable to obtain lock\n");
01639 if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
01640 return 0;
01641 else
01642 return -1;
01643 }
01644 e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
01645 if (e) {
01646 switch(action) {
01647 case HELPER_CANMATCH:
01648 ast_mutex_unlock(&conlock);
01649 return -1;
01650 case HELPER_EXISTS:
01651 ast_mutex_unlock(&conlock);
01652 return -1;
01653 case HELPER_FINDLABEL:
01654 res = e->priority;
01655 ast_mutex_unlock(&conlock);
01656 return res;
01657 case HELPER_MATCHMORE:
01658 ast_mutex_unlock(&conlock);
01659 return -1;
01660 case HELPER_SPAWN:
01661 newstack++;
01662
01663 case HELPER_EXEC:
01664 app = pbx_findapp(e->app);
01665 ast_mutex_unlock(&conlock);
01666 if (app) {
01667 if (c->context != context)
01668 ast_copy_string(c->context, context, sizeof(c->context));
01669 if (c->exten != exten)
01670 ast_copy_string(c->exten, exten, sizeof(c->exten));
01671 c->priority = priority;
01672 pbx_substitute_variables(passdata, sizeof(passdata), c, e);
01673 if (option_debug) {
01674 ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
01675 snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
01676 snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
01677 pbx_builtin_setvar_helper(c, atmp, atmp2);
01678 }
01679 if (option_verbose > 2)
01680 ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
01681 term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
01682 term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
01683 term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
01684 (newstack ? "in new stack" : "in same stack"));
01685 manager_event(EVENT_FLAG_CALL, "Newexten",
01686 "Channel: %s\r\n"
01687 "Context: %s\r\n"
01688 "Extension: %s\r\n"
01689 "Priority: %d\r\n"
01690 "Application: %s\r\n"
01691 "AppData: %s\r\n"
01692 "Uniqueid: %s\r\n",
01693 c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
01694 res = pbx_exec(c, app, passdata, newstack);
01695 return res;
01696 } else {
01697 ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
01698 return -1;
01699 }
01700 default:
01701 ast_log(LOG_WARNING, "Huh (%d)?\n", action); return -1;
01702 }
01703 } else if (sw) {
01704 switch(action) {
01705 case HELPER_CANMATCH:
01706 ast_mutex_unlock(&conlock);
01707 return -1;
01708 case HELPER_EXISTS:
01709 ast_mutex_unlock(&conlock);
01710 return -1;
01711 case HELPER_MATCHMORE:
01712 ast_mutex_unlock(&conlock);
01713 return -1;
01714 case HELPER_FINDLABEL:
01715 ast_mutex_unlock(&conlock);
01716 return -1;
01717 case HELPER_SPAWN:
01718 newstack++;
01719
01720 case HELPER_EXEC:
01721 ast_mutex_unlock(&conlock);
01722 if (sw->exec)
01723 res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
01724 else {
01725 ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
01726 res = -1;
01727 }
01728 return res;
01729 default:
01730 ast_log(LOG_WARNING, "Huh (%d)?\n", action);
01731 return -1;
01732 }
01733 } else {
01734 ast_mutex_unlock(&conlock);
01735 switch(status) {
01736 case STATUS_NO_CONTEXT:
01737 if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
01738 ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
01739 break;
01740 case STATUS_NO_EXTENSION:
01741 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01742 ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
01743 break;
01744 case STATUS_NO_PRIORITY:
01745 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01746 ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
01747 break;
01748 case STATUS_NO_LABEL:
01749 if (context)
01750 ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
01751 break;
01752 default:
01753 ast_log(LOG_DEBUG, "Shouldn't happen!\n");
01754 }
01755
01756 if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01757 return -1;
01758 else
01759 return 0;
01760 }
01761
01762 }
01763
01764
01765 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
01766 {
01767 struct ast_exten *e;
01768 struct ast_switch *sw;
01769 char *data;
01770 const char *foundcontext = NULL;
01771 int status = 0;
01772 char *incstack[AST_PBX_MAX_STACK];
01773 int stacklen = 0;
01774
01775 if (ast_mutex_lock(&conlock)) {
01776 ast_log(LOG_WARNING, "Unable to obtain lock\n");
01777 return NULL;
01778 }
01779 e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
01780 ast_mutex_unlock(&conlock);
01781 return e;
01782 }
01783
01784
01785 static int ast_extension_state2(struct ast_exten *e)
01786 {
01787 char hint[AST_MAX_EXTENSION] = "";
01788 char *cur, *rest;
01789 int res = -1;
01790 int allunavailable = 1, allbusy = 1, allfree = 1;
01791 int busy = 0, inuse = 0, ring = 0;
01792
01793 if (!e)
01794 return -1;
01795
01796 ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
01797
01798 cur = hint;
01799 do {
01800 rest = strchr(cur, '&');
01801 if (rest) {
01802 *rest = 0;
01803 rest++;
01804 }
01805
01806 res = ast_device_state(cur);
01807 switch (res) {
01808 case AST_DEVICE_NOT_INUSE:
01809 allunavailable = 0;
01810 allbusy = 0;
01811 break;
01812 case AST_DEVICE_INUSE:
01813 inuse = 1;
01814 allunavailable = 0;
01815 allfree = 0;
01816 break;
01817 case AST_DEVICE_RINGING:
01818 ring = 1;
01819 allunavailable = 0;
01820 allfree = 0;
01821 break;
01822 case AST_DEVICE_BUSY:
01823 allunavailable = 0;
01824 allfree = 0;
01825 busy = 1;
01826 break;
01827 case AST_DEVICE_UNAVAILABLE:
01828 case AST_DEVICE_INVALID:
01829 allbusy = 0;
01830 allfree = 0;
01831 break;
01832 default:
01833 allunavailable = 0;
01834 allbusy = 0;
01835 allfree = 0;
01836 }
01837 cur = rest;
01838 } while (cur);
01839
01840 if (!inuse && ring)
01841 return AST_EXTENSION_RINGING;
01842 if (inuse && ring)
01843 return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
01844 if (inuse)
01845 return AST_EXTENSION_INUSE;
01846 if (allfree)
01847 return AST_EXTENSION_NOT_INUSE;
01848 if (allbusy)
01849 return AST_EXTENSION_BUSY;
01850 if (allunavailable)
01851 return AST_EXTENSION_UNAVAILABLE;
01852 if (busy)
01853 return AST_EXTENSION_INUSE;
01854
01855 return AST_EXTENSION_NOT_INUSE;
01856 }
01857
01858
01859 const char *ast_extension_state2str(int extension_state)
01860 {
01861 int i;
01862
01863 for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
01864 if (extension_states[i].extension_state == extension_state) {
01865 return extension_states[i].text;
01866 }
01867 }
01868 return "Unknown";
01869 }
01870
01871
01872 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
01873 {
01874 struct ast_exten *e;
01875
01876 e = ast_hint_extension(c, context, exten);
01877 if (!e)
01878 return -1;
01879
01880 return ast_extension_state2(e);
01881 }
01882
01883 void ast_hint_state_changed(const char *device)
01884 {
01885 struct ast_hint *hint;
01886 struct ast_state_cb *cblist;
01887 char buf[AST_MAX_EXTENSION];
01888 char *parse;
01889 char *cur;
01890 int state;
01891
01892 ast_mutex_lock(&hintlock);
01893
01894 for (hint = hints; hint; hint = hint->next) {
01895 ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
01896 parse = buf;
01897 for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
01898 if (strcasecmp(cur, device))
01899 continue;
01900
01901
01902 state = ast_extension_state2(hint->exten);
01903
01904 if ((state == -1) || (state == hint->laststate))
01905 continue;
01906
01907
01908
01909
01910 for (cblist = statecbs; cblist; cblist = cblist->next)
01911 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
01912
01913
01914 for (cblist = hint->callbacks; cblist; cblist = cblist->next)
01915 cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
01916
01917 hint->laststate = state;
01918 break;
01919 }
01920 }
01921
01922 ast_mutex_unlock(&hintlock);
01923 }
01924
01925
01926 int ast_extension_state_add(const char *context, const char *exten,
01927 ast_state_cb_type callback, void *data)
01928 {
01929 struct ast_hint *list;
01930 struct ast_state_cb *cblist;
01931 struct ast_exten *e;
01932
01933
01934 if (!context && !exten) {
01935 ast_mutex_lock(&hintlock);
01936
01937 cblist = statecbs;
01938 while (cblist) {
01939 if (cblist->callback == callback) {
01940 cblist->data = data;
01941 ast_mutex_unlock(&hintlock);
01942 return 0;
01943 }
01944 cblist = cblist->next;
01945 }
01946
01947
01948 cblist = malloc(sizeof(struct ast_state_cb));
01949 if (!cblist) {
01950 ast_mutex_unlock(&hintlock);
01951 return -1;
01952 }
01953 memset(cblist, 0, sizeof(struct ast_state_cb));
01954 cblist->id = 0;
01955 cblist->callback = callback;
01956 cblist->data = data;
01957
01958 cblist->next = statecbs;
01959 statecbs = cblist;
01960
01961 ast_mutex_unlock(&hintlock);
01962 return 0;
01963 }
01964
01965 if (!context || !exten)
01966 return -1;
01967
01968
01969 e = ast_hint_extension(NULL, context, exten);
01970 if (!e) {
01971 return -1;
01972 }
01973
01974
01975 ast_mutex_lock(&hintlock);
01976 list = hints;
01977
01978 while (list) {
01979 if (list->exten == e)
01980 break;
01981 list = list->next;
01982 }
01983
01984 if (!list) {
01985
01986 ast_mutex_unlock(&hintlock);
01987 return -1;
01988 }
01989
01990
01991 cblist = malloc(sizeof(struct ast_state_cb));
01992 if (!cblist) {
01993 ast_mutex_unlock(&hintlock);
01994 return -1;
01995 }
01996 memset(cblist, 0, sizeof(struct ast_state_cb));
01997 cblist->id = stateid++;
01998 cblist->callback = callback;
01999 cblist->data = data;
02000
02001 cblist->next = list->callbacks;
02002 list->callbacks = cblist;
02003
02004 ast_mutex_unlock(&hintlock);
02005 return cblist->id;
02006 }
02007
02008
02009 int ast_extension_state_del(int id, ast_state_cb_type callback)
02010 {
02011 struct ast_hint *list;
02012 struct ast_state_cb *cblist, *cbprev;
02013
02014 if (!id && !callback)
02015 return -1;
02016
02017 ast_mutex_lock(&hintlock);
02018
02019
02020 if (!id) {
02021 cbprev = NULL;
02022 cblist = statecbs;
02023 while (cblist) {
02024 if (cblist->callback == callback) {
02025 if (!cbprev)
02026 statecbs = cblist->next;
02027 else
02028 cbprev->next = cblist->next;
02029
02030 free(cblist);
02031
02032 ast_mutex_unlock(&hintlock);
02033 return 0;
02034 }
02035 cbprev = cblist;
02036 cblist = cblist->next;
02037 }
02038
02039 ast_mutex_unlock(&hintlock);
02040 return -1;
02041 }
02042
02043
02044
02045 list = hints;
02046 while (list) {
02047 cblist = list->callbacks;
02048 cbprev = NULL;
02049 while (cblist) {
02050 if (cblist->id==id) {
02051 if (!cbprev)
02052 list->callbacks = cblist->next;
02053 else
02054 cbprev->next = cblist->next;
02055
02056 free(cblist);
02057
02058 ast_mutex_unlock(&hintlock);
02059 return 0;
02060 }
02061 cbprev = cblist;
02062 cblist = cblist->next;
02063 }
02064 list = list->next;
02065 }
02066
02067 ast_mutex_unlock(&hintlock);
02068 return -1;
02069 }
02070
02071
02072 static int ast_add_hint(struct ast_exten *e)
02073 {
02074 struct ast_hint *list;
02075
02076 if (!e)
02077 return -1;
02078
02079 ast_mutex_lock(&hintlock);
02080 list = hints;
02081
02082
02083 while (list) {
02084 if (list->exten == e) {
02085 ast_mutex_unlock(&hintlock);
02086 if (option_debug > 1)
02087 ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02088 return -1;
02089 }
02090 list = list->next;
02091 }
02092
02093 if (option_debug > 1)
02094 ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02095
02096 list = malloc(sizeof(struct ast_hint));
02097 if (!list) {
02098 ast_mutex_unlock(&hintlock);
02099 if (option_debug > 1)
02100 ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
02101 return -1;
02102 }
02103
02104 memset(list, 0, sizeof(struct ast_hint));
02105 list->exten = e;
02106 list->laststate = ast_extension_state2(e);
02107 list->next = hints;
02108 hints = list;
02109
02110 ast_mutex_unlock(&hintlock);
02111 return 0;
02112 }
02113
02114
02115 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
02116 {
02117 struct ast_hint *list;
02118
02119 ast_mutex_lock(&hintlock);
02120 list = hints;
02121
02122 while(list) {
02123 if (list->exten == oe) {
02124 list->exten = ne;
02125 ast_mutex_unlock(&hintlock);
02126 return 0;
02127 }
02128 list = list->next;
02129 }
02130 ast_mutex_unlock(&hintlock);
02131
02132 return -1;
02133 }
02134
02135
02136 static int ast_remove_hint(struct ast_exten *e)
02137 {
02138
02139 struct ast_hint *list, *prev = NULL;
02140 struct ast_state_cb *cblist, *cbprev;
02141
02142 if (!e)
02143 return -1;
02144
02145 ast_mutex_lock(&hintlock);
02146
02147 list = hints;
02148 while(list) {
02149 if (list->exten==e) {
02150 cbprev = NULL;
02151 cblist = list->callbacks;
02152 while (cblist) {
02153
02154 cbprev = cblist;
02155 cblist = cblist->next;
02156 cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
02157 free(cbprev);
02158 }
02159 list->callbacks = NULL;
02160
02161 if (!prev)
02162 hints = list->next;
02163 else
02164 prev->next = list->next;
02165 free(list);
02166
02167 ast_mutex_unlock(&hintlock);
02168 return 0;
02169 } else {
02170 prev = list;
02171 list = list->next;
02172 }
02173 }
02174
02175 ast_mutex_unlock(&hintlock);
02176 return -1;
02177 }
02178
02179
02180
02181 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
02182 {
02183 struct ast_exten *e;
02184 void *tmp;
02185
02186 e = ast_hint_extension(c, context, exten);
02187 if (e) {
02188 if (hint)
02189 ast_copy_string(hint, ast_get_extension_app(e), hintsize);
02190 if (name) {
02191 tmp = ast_get_extension_app_data(e);
02192 if (tmp)
02193 ast_copy_string(name, (char *) tmp, namesize);
02194 }
02195 return -1;
02196 }
02197 return 0;
02198 }
02199
02200 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02201 {
02202 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
02203 }
02204
02205 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
02206 {
02207 return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
02208 }
02209
02210 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
02211 {
02212 return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
02213 }
02214
02215 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02216 {
02217 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
02218 }
02219
02220 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02221 {
02222 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
02223 }
02224
02225 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02226 {
02227 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
02228 }
02229
02230 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02231 {
02232 return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
02233 }
02234
02235 static int __ast_pbx_run(struct ast_channel *c)
02236 {
02237 int firstpass = 1;
02238 int digit;
02239 char exten[256];
02240 int pos;
02241 int waittime;
02242 int res=0;
02243 int autoloopflag;
02244
02245
02246 if (c->pbx)
02247 ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
02248 c->pbx = malloc(sizeof(struct ast_pbx));
02249 if (!c->pbx) {
02250 ast_log(LOG_ERROR, "Out of memory\n");
02251 return -1;
02252 }
02253 if (c->amaflags) {
02254 if (!c->cdr) {
02255 c->cdr = ast_cdr_alloc();
02256 if (!c->cdr) {
02257 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
02258 free(c->pbx);
02259 return -1;
02260 }
02261 ast_cdr_init(c->cdr, c);
02262 }
02263 }
02264 memset(c->pbx, 0, sizeof(struct ast_pbx));
02265
02266 c->pbx->rtimeout = 10;
02267 c->pbx->dtimeout = 5;
02268
02269 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
02270 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
02271
02272
02273 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02274
02275 if (option_verbose > 1)
02276 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);
02277 ast_copy_string(c->exten, "s", sizeof(c->exten));
02278 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02279
02280 if (option_verbose > 1)
02281 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);
02282 ast_copy_string(c->context, "default", sizeof(c->context));
02283 }
02284 c->priority = 1;
02285 }
02286 if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
02287 ast_cdr_start(c->cdr);
02288 for(;;) {
02289 pos = 0;
02290 digit = 0;
02291 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02292 memset(exten, 0, sizeof(exten));
02293 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02294
02295 if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
02296 (res == '*') || (res == '#')) {
02297 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
02298 memset(exten, 0, sizeof(exten));
02299 pos = 0;
02300 exten[pos++] = digit = res;
02301 break;
02302 }
02303 switch(res) {
02304 case AST_PBX_KEEPALIVE:
02305 if (option_debug)
02306 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02307 else if (option_verbose > 1)
02308 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02309 goto out;
02310 break;
02311 default:
02312 if (option_debug)
02313 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02314 else if (option_verbose > 1)
02315 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02316 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02317 c->_softhangup =0;
02318 break;
02319 }
02320
02321 if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02322 break;
02323 }
02324
02325 if (c->cdr) {
02326 ast_cdr_update(c);
02327 }
02328 goto out;
02329 }
02330 }
02331 if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
02332 ast_copy_string(c->exten, "T", sizeof(c->exten));
02333
02334 c->whentohangup = 0;
02335 c->priority = 0;
02336 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
02337 } else if (c->_softhangup) {
02338 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
02339 c->exten, c->priority);
02340 goto out;
02341 }
02342 firstpass = 0;
02343 c->priority++;
02344 }
02345 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
02346
02347 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02348 if (option_verbose > 2)
02349 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
02350 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
02351 ast_copy_string(c->exten, "i", sizeof(c->exten));
02352 c->priority = 1;
02353 } else {
02354 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
02355 c->name, c->exten, c->context);
02356 goto out;
02357 }
02358 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02359
02360 c->_softhangup = 0;
02361 } else {
02362
02363 waittime = 0;
02364 if (digit)
02365 waittime = c->pbx->dtimeout;
02366 else if (!autofallthrough)
02367 waittime = c->pbx->rtimeout;
02368 if (waittime) {
02369 while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
02370
02371
02372 digit = ast_waitfordigit(c, waittime * 1000);
02373 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02374 c->_softhangup = 0;
02375 } else {
02376 if (!digit)
02377
02378 break;
02379 if (digit < 0)
02380
02381 goto out;
02382 exten[pos++] = digit;
02383 waittime = c->pbx->dtimeout;
02384 }
02385 }
02386 if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
02387
02388 ast_copy_string(c->exten, exten, sizeof(c->exten));
02389 c->priority = 1;
02390 } else {
02391
02392 if (!ast_strlen_zero(exten)) {
02393
02394 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02395 if (option_verbose > 2)
02396 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
02397 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
02398 ast_copy_string(c->exten, "i", sizeof(c->exten));
02399 c->priority = 1;
02400 } else {
02401 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
02402 goto out;
02403 }
02404 } else {
02405
02406 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
02407 if (option_verbose > 2)
02408 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
02409 ast_copy_string(c->exten, "t", sizeof(c->exten));
02410 c->priority = 1;
02411 } else {
02412 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
02413 goto out;
02414 }
02415 }
02416 }
02417 if (c->cdr) {
02418 if (option_verbose > 2)
02419 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
02420 ast_cdr_update(c);
02421 }
02422 } else {
02423 char *status;
02424
02425 status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
02426 if (!status)
02427 status = "UNKNOWN";
02428 if (option_verbose > 2)
02429 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
02430 if (!strcasecmp(status, "CONGESTION"))
02431 res = pbx_builtin_congestion(c, "10");
02432 else if (!strcasecmp(status, "CHANUNAVAIL"))
02433 res = pbx_builtin_congestion(c, "10");
02434 else if (!strcasecmp(status, "BUSY"))
02435 res = pbx_builtin_busy(c, "10");
02436 goto out;
02437 }
02438 }
02439 }
02440 if (firstpass)
02441 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
02442 out:
02443 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
02444 c->exten[0] = 'h';
02445 c->exten[1] = '\0';
02446 c->priority = 1;
02447 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02448 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02449
02450 if (option_debug)
02451 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02452 else if (option_verbose > 1)
02453 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02454 break;
02455 }
02456 c->priority++;
02457 }
02458 }
02459 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02460
02461 pbx_destroy(c->pbx);
02462 c->pbx = NULL;
02463 if (res != AST_PBX_KEEPALIVE)
02464 ast_hangup(c);
02465 return 0;
02466 }
02467
02468
02469 static int increase_call_count(const struct ast_channel *c)
02470 {
02471 int failed = 0;
02472 double curloadavg;
02473 ast_mutex_lock(&maxcalllock);
02474 if (option_maxcalls) {
02475 if (countcalls >= option_maxcalls) {
02476 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
02477 failed = -1;
02478 }
02479 }
02480 if (option_maxload) {
02481 getloadavg(&curloadavg, 1);
02482 if (curloadavg >= option_maxload) {
02483 ast_log(LOG_NOTICE, "Maximum loadavg limit of %lf load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
02484 failed = -1;
02485 }
02486 }
02487 if (!failed)
02488 countcalls++;
02489 ast_mutex_unlock(&maxcalllock);
02490
02491 return failed;
02492 }
02493
02494 static void decrease_call_count(void)
02495 {
02496 ast_mutex_lock(&maxcalllock);
02497 if (countcalls > 0)
02498 countcalls--;
02499 ast_mutex_unlock(&maxcalllock);
02500 }
02501
02502 static void *pbx_thread(void *data)
02503 {
02504
02505
02506
02507
02508
02509
02510
02511
02512 struct ast_channel *c = data;
02513
02514 __ast_pbx_run(c);
02515 decrease_call_count();
02516
02517 pthread_exit(NULL);
02518
02519 return NULL;
02520 }
02521
02522 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
02523 {
02524 pthread_t t;
02525 pthread_attr_t attr;
02526
02527 if (!c) {
02528 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
02529 return AST_PBX_FAILED;
02530 }
02531
02532 if (increase_call_count(c))
02533 return AST_PBX_CALL_LIMIT;
02534
02535
02536 pthread_attr_init(&attr);
02537 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02538 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
02539 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
02540 return AST_PBX_FAILED;
02541 }
02542
02543 return AST_PBX_SUCCESS;
02544 }
02545
02546 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
02547 {
02548 enum ast_pbx_result res = AST_PBX_SUCCESS;
02549
02550 if (increase_call_count(c))
02551 return AST_PBX_CALL_LIMIT;
02552
02553 res = __ast_pbx_run(c);
02554 decrease_call_count();
02555
02556 return res;
02557 }
02558
02559 int ast_active_calls(void)
02560 {
02561 return countcalls;
02562 }
02563
02564 int pbx_set_autofallthrough(int newval)
02565 {
02566 int oldval;
02567 oldval = autofallthrough;
02568 if (oldval != newval)
02569 autofallthrough = newval;
02570 return oldval;
02571 }
02572
02573
02574
02575
02576
02577
02578 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
02579 {
02580 struct ast_context *c;
02581
02582 if (ast_lock_contexts()) return -1;
02583
02584
02585 c = ast_walk_contexts(NULL);
02586 while (c) {
02587
02588 if (!strcmp(ast_get_context_name(c), context)) {
02589 int ret;
02590
02591 ret = ast_context_remove_include2(c, include, registrar);
02592
02593 ast_unlock_contexts();
02594
02595
02596 return ret;
02597 }
02598 c = ast_walk_contexts(c);
02599 }
02600
02601
02602 ast_unlock_contexts();
02603 return -1;
02604 }
02605
02606
02607
02608
02609
02610
02611
02612
02613
02614 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
02615 {
02616 struct ast_include *i, *pi = NULL;
02617
02618 if (ast_mutex_lock(&con->lock)) return -1;
02619
02620
02621 i = con->includes;
02622 while (i) {
02623
02624 if (!strcmp(i->name, include) &&
02625 (!registrar || !strcmp(i->registrar, registrar))) {
02626
02627 if (pi)
02628 pi->next = i->next;
02629 else
02630 con->includes = i->next;
02631
02632 free(i);
02633 ast_mutex_unlock(&con->lock);
02634 return 0;
02635 }
02636 pi = i;
02637 i = i->next;
02638 }
02639
02640
02641 ast_mutex_unlock(&con->lock);
02642 return -1;
02643 }
02644
02645
02646
02647
02648
02649
02650 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
02651 {
02652 struct ast_context *c;
02653
02654 if (ast_lock_contexts()) return -1;
02655
02656
02657 c = ast_walk_contexts(NULL);
02658 while (c) {
02659
02660 if (!strcmp(ast_get_context_name(c), context)) {
02661 int ret;
02662
02663 ret = ast_context_remove_switch2(c, sw, data, registrar);
02664
02665 ast_unlock_contexts();
02666
02667
02668 return ret;
02669 }
02670 c = ast_walk_contexts(c);
02671 }
02672
02673
02674 ast_unlock_contexts();
02675 return -1;
02676 }
02677
02678
02679
02680
02681
02682
02683
02684
02685
02686 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
02687 {
02688 struct ast_sw *i, *pi = NULL;
02689
02690 if (ast_mutex_lock(&con->lock)) return -1;
02691
02692
02693 i = con->alts;
02694 while (i) {
02695
02696 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
02697 (!registrar || !strcmp(i->registrar, registrar))) {
02698
02699 if (pi)
02700 pi->next = i->next;
02701 else
02702 con->alts = i->next;
02703
02704 free(i);
02705 ast_mutex_unlock(&con->lock);
02706 return 0;
02707 }
02708 pi = i;
02709 i = i->next;
02710 }
02711
02712
02713 ast_mutex_unlock(&con->lock);
02714 return -1;
02715 }
02716
02717
02718
02719
02720
02721
02722 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
02723 {
02724 struct ast_context *c;
02725
02726 if (ast_lock_contexts()) return -1;
02727
02728
02729 c = ast_walk_contexts(NULL);
02730 while (c) {
02731
02732 if (!strcmp(ast_get_context_name(c), context)) {
02733
02734 int ret = ast_context_remove_extension2(c, extension, priority,
02735 registrar);
02736
02737 ast_unlock_contexts();
02738 return ret;
02739 }
02740 c = ast_walk_contexts(c);
02741 }
02742
02743
02744 ast_unlock_contexts();
02745 return -1;
02746 }
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757
02758 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
02759 {
02760 struct ast_exten *exten, *prev_exten = NULL;
02761
02762 if (ast_mutex_lock(&con->lock)) return -1;
02763
02764
02765 exten = con->root;
02766 while (exten) {
02767
02768
02769 if (!strcmp(exten->exten, extension) &&
02770 (!registrar || !strcmp(exten->registrar, registrar))) {
02771 struct ast_exten *peer;
02772
02773
02774 if (priority == 0) {
02775
02776 if (prev_exten)
02777 prev_exten->next = exten->next;
02778 else
02779 con->root = exten->next;
02780
02781
02782 peer = exten;
02783 while (peer) {
02784 exten = peer->peer;
02785
02786 if (!peer->priority==PRIORITY_HINT)
02787 ast_remove_hint(peer);
02788
02789 peer->datad(peer->data);
02790 free(peer);
02791
02792 peer = exten;
02793 }
02794
02795 ast_mutex_unlock(&con->lock);
02796 return 0;
02797 } else {
02798
02799 struct ast_exten *previous_peer = NULL;
02800
02801 peer = exten;
02802 while (peer) {
02803
02804 if (peer->priority == priority &&
02805 (!registrar || !strcmp(peer->registrar, registrar) )) {
02806
02807 if (!previous_peer) {
02808
02809 if (prev_exten) {
02810
02811
02812
02813 if (peer->peer) {
02814 prev_exten->next = peer->peer;
02815 peer->peer->next = exten->next;
02816 } else
02817 prev_exten->next = exten->next;
02818 } else {
02819
02820
02821
02822 if (peer->peer)
02823 con->root = peer->peer;
02824 else
02825 con->root = exten->next;
02826 }
02827 } else {
02828
02829 previous_peer->peer = peer->peer;
02830 }
02831
02832
02833 if (peer->priority==PRIORITY_HINT)
02834 ast_remove_hint(peer);
02835 peer->datad(peer->data);
02836 free(peer);
02837
02838 ast_mutex_unlock(&con->lock);
02839 return 0;
02840 } else {
02841
02842 previous_peer = peer;
02843 peer = peer->peer;
02844 }
02845 }
02846
02847 ast_mutex_unlock(&con->lock);
02848 return -1;
02849 }
02850 }
02851
02852 prev_exten = exten;
02853 exten = exten->next;
02854 }
02855
02856
02857 ast_mutex_unlock(&con->lock);
02858 return -1;
02859 }
02860
02861
02862
02863 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
02864 {
02865 struct ast_app *tmp, *prev, *cur;
02866 char tmps[80];
02867 int length;
02868 length = sizeof(struct ast_app);
02869 length += strlen(app) + 1;
02870 if (ast_mutex_lock(&applock)) {
02871 ast_log(LOG_ERROR, "Unable to lock application list\n");
02872 return -1;
02873 }
02874 tmp = apps;
02875 while(tmp) {
02876 if (!strcasecmp(app, tmp->name)) {
02877 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02878 ast_mutex_unlock(&applock);
02879 return -1;
02880 }
02881 tmp = tmp->next;
02882 }
02883 tmp = malloc(length);
02884 if (tmp) {
02885 memset(tmp, 0, length);
02886 strcpy(tmp->name, app);
02887 tmp->execute = execute;
02888 tmp->synopsis = synopsis;
02889 tmp->description = description;
02890
02891 cur = apps;
02892 prev = NULL;
02893 while(cur) {
02894 if (strcasecmp(tmp->name, cur->name) < 0)
02895 break;
02896 prev = cur;
02897 cur = cur->next;
02898 }
02899 if (prev) {
02900 tmp->next = prev->next;
02901 prev->next = tmp;
02902 } else {
02903 tmp->next = apps;
02904 apps = tmp;
02905 }
02906 } else {
02907 ast_log(LOG_ERROR, "Out of memory\n");
02908 ast_mutex_unlock(&applock);
02909 return -1;
02910 }
02911 if (option_verbose > 1)
02912 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02913 ast_mutex_unlock(&applock);
02914 return 0;
02915 }
02916
02917 int ast_register_switch(struct ast_switch *sw)
02918 {
02919 struct ast_switch *tmp, *prev=NULL;
02920 if (ast_mutex_lock(&switchlock)) {
02921 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02922 return -1;
02923 }
02924 tmp = switches;
02925 while(tmp) {
02926 if (!strcasecmp(tmp->name, sw->name))
02927 break;
02928 prev = tmp;
02929 tmp = tmp->next;
02930 }
02931 if (tmp) {
02932 ast_mutex_unlock(&switchlock);
02933 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
02934 return -1;
02935 }
02936 sw->next = NULL;
02937 if (prev)
02938 prev->next = sw;
02939 else
02940 switches = sw;
02941 ast_mutex_unlock(&switchlock);
02942 return 0;
02943 }
02944
02945 void ast_unregister_switch(struct ast_switch *sw)
02946 {
02947 struct ast_switch *tmp, *prev=NULL;
02948 if (ast_mutex_lock(&switchlock)) {
02949 ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02950 return;
02951 }
02952 tmp = switches;
02953 while(tmp) {
02954 if (tmp == sw) {
02955 if (prev)
02956 prev->next = tmp->next;
02957 else
02958 switches = tmp->next;
02959 tmp->next = NULL;
02960 break;
02961 }
02962 prev = tmp;
02963 tmp = tmp->next;
02964 }
02965 ast_mutex_unlock(&switchlock);
02966 }
02967
02968
02969
02970
02971 static char show_application_help[] =
02972 "Usage: show application <application> [<application> [<application> [...]]]\n"
02973 " Describes a particular application.\n";
02974
02975 static char show_functions_help[] =
02976 "Usage: show functions\n"
02977 " List builtin functions accessable as $(function args)\n";
02978
02979 static char show_function_help[] =
02980 "Usage: show function <function>\n"
02981 " Describe a particular dialplan function.\n";
02982
02983 static char show_applications_help[] =
02984 "Usage: show applications [{like|describing} <text>]\n"
02985 " List applications which are currently available.\n"
02986 " If 'like', <text> will be a substring of the app name\n"
02987 " If 'describing', <text> will be a substring of the description\n";
02988
02989 static char show_dialplan_help[] =
02990 "Usage: show dialplan [exten@][context]\n"
02991 " Show dialplan\n";
02992
02993 static char show_switches_help[] =
02994 "Usage: show switches\n"
02995 " Show registered switches\n";
02996
02997 static char show_hints_help[] =
02998 "Usage: show hints\n"
02999 " Show registered hints\n";
03000
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016 static char *complete_show_application(char *line, char *word,
03017 int pos, int state)
03018 {
03019 struct ast_app *a;
03020 int which = 0;
03021
03022
03023 if (ast_mutex_lock(&applock)) {
03024 ast_log(LOG_ERROR, "Unable to lock application list\n");
03025 return NULL;
03026 }
03027
03028
03029 a = apps;
03030 while (a) {
03031
03032 if (!strncasecmp(word, a->name, strlen(word))) {
03033
03034 if (++which > state) {
03035 char *ret = strdup(a->name);
03036 ast_mutex_unlock(&applock);
03037 return ret;
03038 }
03039 }
03040 a = a->next;
03041 }
03042
03043
03044 ast_mutex_unlock(&applock);
03045 return NULL;
03046 }
03047
03048 static int handle_show_application(int fd, int argc, char *argv[])
03049 {
03050 struct ast_app *a;
03051 int app, no_registered_app = 1;
03052
03053 if (argc < 3) return RESULT_SHOWUSAGE;
03054
03055
03056 if (ast_mutex_lock(&applock)) {
03057 ast_log(LOG_ERROR, "Unable to lock application list\n");
03058 return -1;
03059 }
03060
03061
03062 a = apps;
03063 while (a) {
03064
03065
03066 for (app = 2; app < argc; app++) {
03067 if (!strcasecmp(a->name, argv[app])) {
03068
03069 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03070 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03071 int synopsis_size, description_size;
03072
03073 no_registered_app = 0;
03074
03075 if (a->synopsis)
03076 synopsis_size = strlen(a->synopsis) + 23;
03077 else
03078 synopsis_size = strlen("Not available") + 23;
03079 synopsis = alloca(synopsis_size);
03080
03081 if (a->description)
03082 description_size = strlen(a->description) + 23;
03083 else
03084 description_size = strlen("Not available") + 23;
03085 description = alloca(description_size);
03086
03087 if (synopsis && description) {
03088 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
03089 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03090 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03091 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03092 term_color(synopsis,
03093 a->synopsis ? a->synopsis : "Not available",
03094 COLOR_CYAN, 0, synopsis_size);
03095 term_color(description,
03096 a->description ? a->description : "Not available",
03097 COLOR_CYAN, 0, description_size);
03098
03099 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03100 } else {
03101
03102 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
03103 "[Synopsis]\n %s\n\n"
03104 "[Description]\n%s\n",
03105 a->name,
03106 a->synopsis ? a->synopsis : "Not available",
03107 a->description ? a->description : "Not available");
03108 }
03109 }
03110 }
03111 a = a->next;
03112 }
03113
03114 ast_mutex_unlock(&applock);
03115
03116
03117 if (no_registered_app) {
03118 ast_cli(fd, "Your application(s) is (are) not registered\n");
03119 return RESULT_FAILURE;
03120 }
03121
03122 return RESULT_SUCCESS;
03123 }
03124
03125
03126 static int handle_show_hints(int fd, int argc, char *argv[])
03127 {
03128 struct ast_hint *hint;
03129 int num = 0;
03130 int watchers;
03131 struct ast_state_cb *watcher;
03132
03133 if (!hints) {
03134 ast_cli(fd, "There are no registered dialplan hints\n");
03135 return RESULT_SUCCESS;
03136 }
03137
03138 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
03139 if (ast_mutex_lock(&hintlock)) {
03140 ast_log(LOG_ERROR, "Unable to lock hints\n");
03141 return -1;
03142 }
03143 hint = hints;
03144 while (hint) {
03145 watchers = 0;
03146 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
03147 watchers++;
03148 ast_cli(fd, " %-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
03149 ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten),
03150 ast_extension_state2str(hint->laststate), watchers);
03151 num++;
03152 hint = hint->next;
03153 }
03154 ast_cli(fd, "----------------\n");
03155 ast_cli(fd, "- %d hints registered\n", num);
03156 ast_mutex_unlock(&hintlock);
03157 return RESULT_SUCCESS;
03158 }
03159
03160
03161 static int handle_show_switches(int fd, int argc, char *argv[])
03162 {
03163 struct ast_switch *sw;
03164 if (!switches) {
03165 ast_cli(fd, "There are no registered alternative switches\n");
03166 return RESULT_SUCCESS;
03167 }
03168
03169 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
03170 if (ast_mutex_lock(&switchlock)) {
03171 ast_log(LOG_ERROR, "Unable to lock switches\n");
03172 return -1;
03173 }
03174 sw = switches;
03175 while (sw) {
03176 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
03177 sw = sw->next;
03178 }
03179 ast_mutex_unlock(&switchlock);
03180 return RESULT_SUCCESS;
03181 }
03182
03183
03184
03185
03186 static int handle_show_applications(int fd, int argc, char *argv[])
03187 {
03188 struct ast_app *a;
03189 int like=0, describing=0;
03190 int total_match = 0;
03191 int total_apps = 0;
03192
03193
03194 if (ast_mutex_lock(&applock)) {
03195 ast_log(LOG_ERROR, "Unable to lock application list\n");
03196 return -1;
03197 }
03198
03199
03200 if (!apps) {
03201 ast_cli(fd, "There are no registered applications\n");
03202 ast_mutex_unlock(&applock);
03203 return -1;
03204 }
03205
03206
03207 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
03208 like = 1;
03209 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
03210 describing = 1;
03211 }
03212
03213
03214 if ((!like) && (!describing)) {
03215 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
03216 } else {
03217 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
03218 }
03219
03220
03221 for (a = apps; a; a = a->next) {
03222
03223 int printapp=0;
03224 total_apps++;
03225 if (like) {
03226 if (strcasestr(a->name, argv[3])) {
03227 printapp = 1;
03228 total_match++;
03229 }
03230 } else if (describing) {
03231 if (a->description) {
03232
03233 int i;
03234 printapp = 1;
03235 for (i=3; i<argc; i++) {
03236 if (!strcasestr(a->description, argv[i])) {
03237 printapp = 0;
03238 } else {
03239 total_match++;
03240 }
03241 }
03242 }
03243 } else {
03244 printapp = 1;
03245 }
03246
03247 if (printapp) {
03248 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03249 }
03250 }
03251 if ((!like) && (!describing)) {
03252 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
03253 } else {
03254 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
03255 }
03256
03257
03258 ast_mutex_unlock(&applock);
03259
03260 return RESULT_SUCCESS;
03261 }
03262
03263 static char *complete_show_applications(char *line, char *word, int pos, int state)
03264 {
03265 if (pos == 2) {
03266 if (ast_strlen_zero(word)) {
03267 switch (state) {
03268 case 0:
03269 return strdup("like");
03270 case 1:
03271 return strdup("describing");
03272 default:
03273 return NULL;
03274 }
03275 } else if (! strncasecmp(word, "like", strlen(word))) {
03276 if (state == 0) {
03277 return strdup("like");
03278 } else {
03279 return NULL;
03280 }
03281 } else if (! strncasecmp(word, "describing", strlen(word))) {
03282 if (state == 0) {
03283 return strdup("describing");
03284 } else {
03285 return NULL;
03286 }
03287 }
03288 }
03289 return NULL;
03290 }
03291
03292
03293
03294
03295 static char *complete_show_dialplan_context(char *line, char *word, int pos,
03296 int state)
03297 {
03298 struct ast_context *c;
03299 int which = 0;
03300
03301
03302 if (pos != 2) return NULL;
03303
03304
03305 if (ast_lock_contexts()) {
03306 ast_log(LOG_ERROR, "Unable to lock context list\n");
03307 return NULL;
03308 }
03309
03310
03311 c = ast_walk_contexts(NULL);
03312 while(c) {
03313
03314 if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
03315
03316 if (++which > state) {
03317
03318 char *ret = strdup(ast_get_context_name(c));
03319 ast_unlock_contexts();
03320 return ret;
03321 }
03322 }
03323 c = ast_walk_contexts(c);
03324 }
03325
03326
03327 ast_unlock_contexts();
03328 return NULL;
03329 }
03330
03331 struct dialplan_counters {
03332 int total_context;
03333 int total_exten;
03334 int total_prio;
03335 int context_existence;
03336 int extension_existence;
03337 };
03338
03339 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, char *includes[])
03340 {
03341 struct ast_context *c;
03342 int res=0, old_total_exten = dpc->total_exten;
03343
03344
03345 if (ast_lock_contexts()) {
03346 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
03347 return -1;
03348 }
03349
03350
03351 for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
03352
03353 if (!context ||
03354 !strcmp(ast_get_context_name(c), context)) {
03355 dpc->context_existence = 1;
03356
03357
03358 if (!ast_lock_context(c)) {
03359 struct ast_exten *e;
03360 struct ast_include *i;
03361 struct ast_ignorepat *ip;
03362 struct ast_sw *sw;
03363 char buf[256], buf2[256];
03364 int context_info_printed = 0;
03365
03366
03367
03368
03369 if (!exten) {
03370 dpc->total_context++;
03371 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03372 ast_get_context_name(c), ast_get_context_registrar(c));
03373 context_info_printed = 1;
03374 }
03375
03376
03377 for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
03378 struct ast_exten *p;
03379 int prio;
03380
03381
03382 if (exten &&
03383 !ast_extension_match(ast_get_extension_name(e), exten))
03384 {
03385
03386
03387 continue;
03388 }
03389
03390 dpc->extension_existence = 1;
03391
03392
03393 if (!context_info_printed) {
03394 dpc->total_context++;
03395 if (rinclude) {
03396
03397 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
03398 ast_get_context_name(c),
03399 ast_get_context_registrar(c));
03400 } else {
03401 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03402 ast_get_context_name(c),
03403 ast_get_context_registrar(c));
03404 }
03405 context_info_printed = 1;
03406 }
03407 dpc->total_prio++;
03408
03409
03410 bzero(buf, sizeof(buf));
03411 snprintf(buf, sizeof(buf), "'%s' =>",
03412 ast_get_extension_name(e));
03413
03414 prio = ast_get_extension_priority(e);
03415 if (prio == PRIORITY_HINT) {
03416 snprintf(buf2, sizeof(buf2),
03417 "hint: %s",
03418 ast_get_extension_app(e));
03419 } else {
03420 snprintf(buf2, sizeof(buf2),
03421 "%d. %s(%s)",
03422 prio,
03423 ast_get_extension_app(e),
03424 (char *)ast_get_extension_app_data(e));
03425 }
03426
03427 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
03428 ast_get_extension_registrar(e));
03429
03430 dpc->total_exten++;
03431
03432 for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
03433 dpc->total_prio++;
03434 bzero((void *)buf2, sizeof(buf2));
03435 bzero((void *)buf, sizeof(buf));
03436 if (ast_get_extension_label(p))
03437 snprintf(buf, sizeof(buf), " [%s]", ast_get_extension_label(p));
03438 prio = ast_get_extension_priority(p);
03439 if (prio == PRIORITY_HINT) {
03440 snprintf(buf2, sizeof(buf2),
03441 "hint: %s",
03442 ast_get_extension_app(p));
03443 } else {
03444 snprintf(buf2, sizeof(buf2),
03445 "%d. %s(%s)",
03446 prio,
03447 ast_get_extension_app(p),
03448 (char *)ast_get_extension_app_data(p));
03449 }
03450
03451 ast_cli(fd," %-17s %-45s [%s]\n",
03452 buf, buf2,
03453 ast_get_extension_registrar(p));
03454 }
03455 }
03456
03457
03458 for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
03459 bzero(buf, sizeof(buf));
03460 snprintf(buf, sizeof(buf), "'%s'",
03461 ast_get_include_name(i));
03462 if (exten) {
03463
03464 if (includecount >= AST_PBX_MAX_STACK) {
03465 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
03466 } else {
03467 int dupe=0;
03468 int x;
03469 for (x=0;x<includecount;x++) {
03470 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
03471 dupe++;
03472 break;
03473 }
03474 }
03475 if (!dupe) {
03476 includes[includecount] = (char *)ast_get_include_name(i);
03477 show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
03478 } else {
03479 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
03480 }
03481 }
03482 } else {
03483 ast_cli(fd, " Include => %-45s [%s]\n",
03484 buf, ast_get_include_registrar(i));
03485 }
03486 }
03487
03488
03489 for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
03490 const char *ipname = ast_get_ignorepat_name(ip);
03491 char ignorepat[AST_MAX_EXTENSION];
03492 snprintf(buf, sizeof(buf), "'%s'", ipname);
03493 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03494 if ((!exten) || ast_extension_match(ignorepat, exten)) {
03495 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
03496 buf, ast_get_ignorepat_registrar(ip));
03497 }
03498 }
03499 if (!rinclude) {
03500 for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
03501 snprintf(buf, sizeof(buf), "'%s/%s'",
03502 ast_get_switch_name(sw),
03503 ast_get_switch_data(sw));
03504 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
03505 buf, ast_get_switch_registrar(sw));
03506 }
03507 }
03508
03509 ast_unlock_context(c);
03510
03511
03512 if (context_info_printed) ast_cli(fd, "\r\n");
03513 }
03514 }
03515 }
03516 ast_unlock_contexts();
03517
03518 if (dpc->total_exten == old_total_exten) {
03519
03520 return -1;
03521 } else {
03522 return res;
03523 }
03524 }
03525
03526 static int handle_show_dialplan(int fd, int argc, char *argv[])
03527 {
03528 char *exten = NULL, *context = NULL;
03529
03530 struct dialplan_counters counters;
03531 char *incstack[AST_PBX_MAX_STACK];
03532 memset(&counters, 0, sizeof(counters));
03533
03534 if (argc != 2 && argc != 3)
03535 return RESULT_SHOWUSAGE;
03536
03537
03538 if (argc == 3) {
03539 char *splitter = ast_strdupa(argv[2]);
03540
03541 if (splitter && strchr(argv[2], '@')) {
03542
03543 exten = strsep(&splitter, "@");
03544 context = splitter;
03545
03546
03547 if (ast_strlen_zero(exten))
03548 exten = NULL;
03549 if (ast_strlen_zero(context))
03550 context = NULL;
03551 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03552 } else {
03553
03554 context = argv[2];
03555 if (ast_strlen_zero(context))
03556 context = NULL;
03557 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03558 }
03559 } else {
03560
03561 show_dialplan_helper(fd, NULL, NULL, &counters, NULL, 0, incstack);
03562 }
03563
03564
03565 if (context && !counters.context_existence) {
03566 ast_cli(fd, "There is no existence of '%s' context\n", context);
03567 return RESULT_FAILURE;
03568 }
03569
03570 if (exten && !counters.extension_existence) {
03571 if (context)
03572 ast_cli(fd, "There is no existence of %s@%s extension\n",
03573 exten, context);
03574 else
03575 ast_cli(fd,
03576 "There is no existence of '%s' extension in all contexts\n",
03577 exten);
03578 return RESULT_FAILURE;
03579 }
03580
03581 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
03582 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
03583 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
03584 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
03585
03586
03587 return RESULT_SUCCESS;
03588 }
03589
03590
03591
03592
03593 static struct ast_cli_entry pbx_cli[] = {
03594 { { "show", "applications", NULL }, handle_show_applications,
03595 "Shows registered dialplan applications", show_applications_help, complete_show_applications },
03596 { { "show", "functions", NULL }, handle_show_functions,
03597 "Shows registered dialplan functions", show_functions_help },
03598 { { "show" , "function", NULL }, handle_show_function,
03599 "Describe a specific dialplan function", show_function_help, complete_show_function },
03600 { { "show", "application", NULL }, handle_show_application,
03601 "Describe a specific dialplan application", show_application_help, complete_show_application },
03602 { { "show", "dialplan", NULL }, handle_show_dialplan,
03603 "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
03604 { { "show", "switches", NULL }, handle_show_switches,
03605 "Show alternative switches", show_switches_help },
03606 { { "show", "hints", NULL }, handle_show_hints,
03607 "Show dialplan hints", show_hints_help },
03608 };
03609
03610 int ast_unregister_application(const char *app)
03611 {
03612 struct ast_app *tmp, *tmpl = NULL;
03613 if (ast_mutex_lock(&applock)) {
03614 ast_log(LOG_ERROR, "Unable to lock application list\n");
03615 return -1;
03616 }
03617 tmp = apps;
03618 while(tmp) {
03619 if (!strcasecmp(app, tmp->name)) {
03620 if (tmpl)
03621 tmpl->next = tmp->next;
03622 else
03623 apps = tmp->next;
03624 if (option_verbose > 1)
03625 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
03626 free(tmp);
03627 ast_mutex_unlock(&applock);
03628 return 0;
03629 }
03630 tmpl = tmp;
03631 tmp = tmp->next;
03632 }
03633 ast_mutex_unlock(&applock);
03634 return -1;
03635 }
03636
03637 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03638 {
03639 struct ast_context *tmp, **local_contexts;
03640 int length;
03641 length = sizeof(struct ast_context);
03642 length += strlen(name) + 1;
03643 if (!extcontexts) {
03644 local_contexts = &contexts;
03645 ast_mutex_lock(&conlock);
03646 } else
03647 local_contexts = extcontexts;
03648
03649 tmp = *local_contexts;
03650 while(tmp) {
03651 if (!strcasecmp(tmp->name, name)) {
03652 ast_mutex_unlock(&conlock);
03653 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
03654 if (!extcontexts)
03655 ast_mutex_unlock(&conlock);
03656 return NULL;
03657 }
03658 tmp = tmp->next;
03659 }
03660 tmp = malloc(length);
03661 if (tmp) {
03662 memset(tmp, 0, length);
03663 ast_mutex_init(&tmp->lock);
03664 strcpy(tmp->name, name);
03665 tmp->root = NULL;
03666 tmp->registrar = registrar;
03667 tmp->next = *local_contexts;
03668 tmp->includes = NULL;
03669 tmp->ignorepats = NULL;
03670 *local_contexts = tmp;
03671 if (option_debug)
03672 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
03673 else if (option_verbose > 2)
03674 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
03675 } else
03676 ast_log(LOG_ERROR, "Out of memory\n");
03677
03678 if (!extcontexts)
03679 ast_mutex_unlock(&conlock);
03680 return tmp;
03681 }
03682
03683 void __ast_context_destroy(struct ast_context *con, const char *registrar);
03684
03685 struct store_hint {
03686 char *context;
03687 char *exten;
03688 struct ast_state_cb *callbacks;
03689 int laststate;
03690 AST_LIST_ENTRY(store_hint) list;
03691 char data[1];
03692 };
03693
03694 AST_LIST_HEAD(store_hints, store_hint);
03695
03696 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
03697 {
03698 struct ast_context *tmp, *lasttmp = NULL;
03699 struct store_hints store;
03700 struct store_hint *this;
03701 struct ast_hint *hint;
03702 struct ast_exten *exten;
03703 int length;
03704 struct ast_state_cb *thiscb, *prevcb;
03705
03706 AST_LIST_HEAD_INIT(&store);
03707
03708
03709
03710
03711
03712
03713
03714
03715
03716 ast_mutex_lock(&conlock);
03717 ast_mutex_lock(&hintlock);
03718
03719
03720 for (hint = hints; hint; hint = hint->next) {
03721 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
03722 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
03723 this = calloc(1, length);
03724 if (!this) {
03725 ast_log(LOG_WARNING, "Could not allocate memory to preserve hint\n");
03726 continue;
03727 }
03728 this->callbacks = hint->callbacks;
03729 hint->callbacks = NULL;
03730 this->laststate = hint->laststate;
03731 this->context = this->data;
03732 strcpy(this->data, hint->exten->parent->name);
03733 this->exten = this->data + strlen(this->context) + 1;
03734 strcpy(this->exten, hint->exten->exten);
03735 AST_LIST_INSERT_HEAD(&store, this, list);
03736 }
03737 }
03738
03739 tmp = *extcontexts;
03740 if (registrar) {
03741 __ast_context_destroy(NULL,registrar);
03742 while (tmp) {
03743 lasttmp = tmp;
03744 tmp = tmp->next;
03745 }
03746 } else {
03747 while (tmp) {
03748 __ast_context_destroy(tmp,tmp->registrar);
03749 lasttmp = tmp;
03750 tmp = tmp->next;
03751 }
03752 }
03753 if (lasttmp) {
03754 lasttmp->next = contexts;
03755 contexts = *extcontexts;
03756 *extcontexts = NULL;
03757 } else
03758 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
03759
03760
03761
03762
03763 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
03764 exten = ast_hint_extension(NULL, this->context, this->exten);
03765
03766 for (hint = hints; hint; hint = hint->next) {
03767 if (hint->exten == exten)
03768 break;
03769 }
03770 if (!exten || !hint) {
03771
03772 prevcb = NULL;
03773 thiscb = this->callbacks;
03774 while (thiscb) {
03775 prevcb = thiscb;
03776 thiscb = thiscb->next;
03777 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
03778 free(prevcb);
03779 }
03780 } else {
03781 thiscb = this->callbacks;
03782 while (thiscb->next)
03783 thiscb = thiscb->next;
03784 thiscb->next = hint->callbacks;
03785 hint->callbacks = this->callbacks;
03786 hint->laststate = this->laststate;
03787 }
03788 free(this);
03789 }
03790
03791 ast_mutex_unlock(&hintlock);
03792 ast_mutex_unlock(&conlock);
03793
03794 return;
03795 }
03796
03797
03798
03799
03800
03801
03802 int ast_context_add_include(const char *context, const char *include, const char *registrar)
03803 {
03804 struct ast_context *c;
03805
03806 if (ast_lock_contexts()) {
03807 errno = EBUSY;
03808 return -1;
03809 }
03810
03811
03812 c = ast_walk_contexts(NULL);
03813 while (c) {
03814
03815 if (!strcmp(ast_get_context_name(c), context)) {
03816 int ret = ast_context_add_include2(c, include, registrar);
03817
03818 ast_unlock_contexts();
03819 return ret;
03820 }
03821 c = ast_walk_contexts(c);
03822 }
03823
03824
03825 ast_unlock_contexts();
03826 errno = ENOENT;
03827 return -1;
03828 }
03829
03830 #define FIND_NEXT \
03831 do { \
03832 c = info; \
03833 while(*c && (*c != '|')) c++; \
03834 if (*c) { *c = '\0'; c++; } else c = NULL; \
03835 } while(0)
03836
03837 static void get_timerange(struct ast_timing *i, char *times)
03838 {
03839 char *e;
03840 int x;
03841 int s1, s2;
03842 int e1, e2;
03843
03844
03845
03846 memset(i->minmask, 0, sizeof(i->minmask));
03847
03848
03849 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
03850 for (x=0; x<24; x++)
03851 i->minmask[x] = (1 << 30) - 1;
03852 return;
03853 }
03854
03855 e = strchr(times, '-');
03856 if (!e) {
03857 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
03858 return;
03859 }
03860 *e = '\0';
03861 e++;
03862 while(*e && !isdigit(*e))
03863 e++;
03864 if (!*e) {
03865 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
03866 return;
03867 }
03868 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
03869 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
03870 return;
03871 }
03872 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
03873 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
03874 return;
03875 }
03876
03877 #if 1
03878 s1 = s1 * 30 + s2/2;
03879 if ((s1 < 0) || (s1 >= 24*30)) {
03880 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
03881 return;
03882 }
03883 e1 = e1 * 30 + e2/2;
03884 if ((e1 < 0) || (e1 >= 24*30)) {
03885 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
03886 return;
03887 }
03888
03889 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
03890 i->minmask[x/30] |= (1 << (x % 30));
03891 }
03892
03893 i->minmask[x/30] |= (1 << (x % 30));
03894 #else
03895 for (cth=0; cth<24; cth++) {
03896
03897 i->minmask[cth] = 0;
03898 for (ctm=0; ctm<30; ctm++) {
03899 if (
03900
03901 (((cth == s1) && (ctm >= s2)) &&
03902 ((cth < e1)))
03903
03904 || (((cth == s1) && (ctm >= s2)) &&
03905 ((cth == e1) && (ctm <= e2)))
03906
03907 || ((cth > s1) &&
03908 (cth < e1))
03909
03910 || ((cth > s1) &&
03911 ((cth == e1) && (ctm <= e2)))
03912 )
03913 i->minmask[cth] |= (1 << (ctm / 2));
03914 }
03915 }
03916 #endif
03917
03918 return;
03919 }
03920
03921 static char *days[] =
03922 {
03923 "sun",
03924 "mon",
03925 "tue",
03926 "wed",
03927 "thu",
03928 "fri",
03929 "sat",
03930 };
03931
03932
03933 static unsigned int get_dow(char *dow)
03934 {
03935 char *c;
03936
03937 int s, e, x;
03938 unsigned int mask;
03939
03940
03941 if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
03942 return (1 << 7) - 1;
03943
03944 c = strchr(dow, '-');
03945 if (c) {
03946 *c = '\0';
03947 c++;
03948 } else
03949 c = NULL;
03950
03951 s = 0;
03952 while((s < 7) && strcasecmp(dow, days[s])) s++;
03953 if (s >= 7) {
03954 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
03955 return 0;
03956 }
03957 if (c) {
03958 e = 0;
03959 while((e < 7) && strcasecmp(c, days[e])) e++;
03960 if (e >= 7) {
03961 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
03962 return 0;
03963 }
03964 } else
03965 e = s;
03966 mask = 0;
03967 for (x=s; x != e; x = (x + 1) % 7) {
03968 mask |= (1 << x);
03969 }
03970
03971 mask |= (1 << x);
03972 return mask;
03973 }
03974
03975 static unsigned int get_day(char *day)
03976 {
03977 char *c;
03978
03979 int s, e, x;
03980 unsigned int mask;
03981
03982
03983 if (ast_strlen_zero(day) || !strcmp(day, "*")) {
03984 mask = (1 << 30) + ((1 << 30) - 1);
03985 return mask;
03986 }
03987
03988 c = strchr(day, '-');
03989 if (c) {
03990 *c = '\0';
03991 c++;
03992 }
03993
03994 if (sscanf(day, "%d", &s) != 1) {
03995 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
03996 return 0;
03997 }
03998 if ((s < 1) || (s > 31)) {
03999 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
04000 return 0;
04001 }
04002 s--;
04003 if (c) {
04004 if (sscanf(c, "%d", &e) != 1) {
04005 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
04006 return 0;
04007 }
04008 if ((e < 1) || (e > 31)) {
04009 ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
04010 return 0;
04011 }
04012 e--;
04013 } else
04014 e = s;
04015 mask = 0;
04016 for (x=s; x!=e; x = (x + 1) % 31) {
04017 mask |= (1 << x);
04018 }
04019 mask |= (1 << x);
04020 return mask;
04021 }
04022
04023 static char *months[] =
04024 {
04025 "jan",
04026 "feb",
04027 "mar",
04028 "apr",
04029 "may",
04030 "jun",
04031 "jul",
04032 "aug",
04033 "sep",
04034 "oct",
04035 "nov",
04036 "dec",
04037 };
04038
04039 static unsigned int get_month(char *mon)
04040 {
04041 char *c;
04042
04043 int s, e, x;
04044 unsigned int mask;
04045
04046
04047 if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
04048 return (1 << 12) - 1;
04049
04050 c = strchr(mon, '-');
04051 if (c) {
04052 *c = '\0';
04053 c++;
04054 }
04055
04056 s = 0;
04057 while((s < 12) && strcasecmp(mon, months[s])) s++;
04058 if (s >= 12) {
04059 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
04060 return 0;
04061 }
04062 if (c) {
04063 e = 0;
04064 while((e < 12) && strcasecmp(mon, months[e])) e++;
04065 if (e >= 12) {
04066 ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
04067 return 0;
04068 }
04069 } else
04070 e = s;
04071 mask = 0;
04072 for (x=s; x!=e; x = (x + 1) % 12) {
04073 mask |= (1 << x);
04074 }
04075
04076 mask |= (1 << x);
04077 return mask;
04078 }
04079
04080 int ast_build_timing(struct ast_timing *i, char *info_in)
04081 {
04082 char info_save[256];
04083 char *info;
04084 char *c;
04085
04086
04087 if (ast_strlen_zero(info_in))
04088 return 0;
04089
04090 ast_copy_string(info_save, info_in, sizeof(info_save));
04091 info = info_save;
04092
04093 i->monthmask = (1 << 12) - 1;
04094 i->daymask = (1 << 30) - 1 + (1 << 30);
04095 i->dowmask = (1 << 7) - 1;
04096
04097 FIND_NEXT;
04098
04099 get_timerange(i, info);
04100 info = c;
04101 if (!info)
04102 return 1;
04103 FIND_NEXT;
04104
04105 i->dowmask = get_dow(info);
04106
04107 info = c;
04108 if (!info)
04109 return 1;
04110 FIND_NEXT;
04111
04112 i->daymask = get_day(info);
04113 info = c;
04114 if (!info)
04115 return 1;
04116 FIND_NEXT;
04117
04118 i->monthmask = get_month(info);
04119
04120 return 1;
04121 }
04122
04123 int ast_check_timing(struct ast_timing *i)
04124 {
04125 struct tm tm;
04126 time_t t;
04127
04128 time(&t);
04129 localtime_r(&t,&tm);
04130
04131
04132 if (!(i->monthmask & (1 << tm.tm_mon))) {
04133 return 0;
04134 }
04135
04136
04137
04138 if (!(i->daymask & (1 << (tm.tm_mday-1))))
04139 return 0;
04140
04141
04142 if (!(i->dowmask & (1 << tm.tm_wday)))
04143 return 0;
04144
04145
04146 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
04147 ast_log(LOG_WARNING, "Insane time...\n");
04148 return 0;
04149 }
04150
04151
04152
04153 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
04154 return 0;
04155
04156
04157 return 1;
04158 }
04159
04160
04161
04162
04163
04164
04165
04166
04167 int ast_context_add_include2(struct ast_context *con, const char *value,
04168 const char *registrar)
04169 {
04170 struct ast_include *new_include;
04171 char *c;
04172 struct ast_include *i, *il = NULL;
04173 int length;
04174 char *p;
04175
04176 length = sizeof(struct ast_include);
04177 length += 2 * (strlen(value) + 1);
04178
04179
04180 if (!(new_include = malloc(length))) {
04181 ast_log(LOG_ERROR, "Out of memory\n");
04182 errno = ENOMEM;
04183 return -1;
04184 }
04185
04186
04187 memset(new_include, 0, length);
04188 p = new_include->stuff;
04189 new_include->name = p;
04190 strcpy(new_include->name, value);
04191 p += strlen(value) + 1;
04192 new_include->rname = p;
04193 strcpy(new_include->rname, value);
04194 c = new_include->rname;
04195
04196 while(*c && (*c != '|'))
04197 c++;
04198
04199 if (*c) {
04200 new_include->hastime = ast_build_timing(&(new_include->timing), c+1);
04201 *c = '\0';
04202 }
04203 new_include->next = NULL;
04204 new_include->registrar = registrar;
04205
04206
04207 if (ast_mutex_lock(&con->lock)) {
04208 free(new_include);
04209 errno = EBUSY;
04210 return -1;
04211 }
04212
04213
04214 i = con->includes;
04215 while (i) {
04216 if (!strcasecmp(i->name, new_include->name)) {
04217 free(new_include);
04218 ast_mutex_unlock(&con->lock);
04219 errno = EEXIST;
04220 return -1;
04221 }
04222 il = i;
04223 i = i->next;
04224 }
04225
04226
04227 if (il)
04228 il->next = new_include;
04229 else
04230 con->includes = new_include;
04231 if (option_verbose > 2)
04232 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04233 ast_mutex_unlock(&con->lock);
04234
04235 return 0;
04236 }
04237
04238
04239
04240
04241
04242
04243 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
04244 {
04245 struct ast_context *c;
04246
04247 if (ast_lock_contexts()) {
04248 errno = EBUSY;
04249 return -1;
04250 }
04251
04252
04253 c = ast_walk_contexts(NULL);
04254 while (c) {
04255
04256 if (!strcmp(ast_get_context_name(c), context)) {
04257 int ret = ast_context_add_switch2(c, sw, data, eval, registrar);
04258
04259 ast_unlock_contexts();
04260 return ret;
04261 }
04262 c = ast_walk_contexts(c);
04263 }
04264
04265
04266 ast_unlock_contexts();
04267 errno = ENOENT;
04268 return -1;
04269 }
04270
04271
04272
04273
04274
04275
04276
04277
04278 int ast_context_add_switch2(struct ast_context *con, const char *value,
04279 const char *data, int eval, const char *registrar)
04280 {
04281 struct ast_sw *new_sw;
04282 struct ast_sw *i, *il = NULL;
04283 int length;
04284 char *p;
04285
04286 length = sizeof(struct ast_sw);
04287 length += strlen(value) + 1;
04288 if (data)
04289 length += strlen(data);
04290 length++;
04291 if (eval) {
04292
04293 length += SWITCH_DATA_LENGTH;
04294 length++;
04295 }
04296
04297
04298 if (!(new_sw = malloc(length))) {
04299 ast_log(LOG_ERROR, "Out of memory\n");
04300 errno = ENOMEM;
04301 return -1;
04302 }
04303
04304
04305 memset(new_sw, 0, length);
04306 p = new_sw->stuff;
04307 new_sw->name = p;
04308 strcpy(new_sw->name, value);
04309 p += strlen(value) + 1;
04310 new_sw->data = p;
04311 if (data) {
04312 strcpy(new_sw->data, data);
04313 p += strlen(data) + 1;
04314 } else {
04315 strcpy(new_sw->data, "");
04316 p++;
04317 }
04318 if (eval)
04319 new_sw->tmpdata = p;
04320 new_sw->next = NULL;
04321 new_sw->eval = eval;
04322 new_sw->registrar = registrar;
04323
04324
04325 if (ast_mutex_lock(&con->lock)) {
04326 free(new_sw);
04327 errno = EBUSY;
04328 return -1;
04329 }
04330
04331
04332 i = con->alts;
04333 while (i) {
04334 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04335 free(new_sw);
04336 ast_mutex_unlock(&con->lock);
04337 errno = EEXIST;
04338 return -1;
04339 }
04340 il = i;
04341 i = i->next;
04342 }
04343
04344
04345 if (il)
04346 il->next = new_sw;
04347 else
04348 con->alts = new_sw;
04349 if (option_verbose > 2)
04350 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04351 ast_mutex_unlock(&con->lock);
04352
04353 return 0;
04354 }
04355
04356
04357
04358
04359
04360 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
04361 {
04362 struct ast_context *c;
04363
04364 if (ast_lock_contexts()) {
04365 errno = EBUSY;
04366 return -1;
04367 }
04368
04369 c = ast_walk_contexts(NULL);
04370 while (c) {
04371 if (!strcmp(ast_get_context_name(c), context)) {
04372 int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
04373 ast_unlock_contexts();
04374 return ret;
04375 }
04376 c = ast_walk_contexts(c);
04377 }
04378
04379 ast_unlock_contexts();
04380 errno = ENOENT;
04381 return -1;
04382 }
04383
04384 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
04385 {
04386 struct ast_ignorepat *ip, *ipl = NULL;
04387
04388 if (ast_mutex_lock(&con->lock)) {
04389 errno = EBUSY;
04390 return -1;
04391 }
04392
04393 ip = con->ignorepats;
04394 while (ip) {
04395 if (!strcmp(ip->pattern, ignorepat) &&
04396 (!registrar || (registrar == ip->registrar))) {
04397 if (ipl) {
04398 ipl->next = ip->next;
04399 free(ip);
04400 } else {
04401 con->ignorepats = ip->next;
04402 free(ip);
04403 }
04404 ast_mutex_unlock(&con->lock);
04405 return 0;
04406 }
04407 ipl = ip; ip = ip->next;
04408 }
04409
04410 ast_mutex_unlock(&con->lock);
04411 errno = EINVAL;
04412 return -1;
04413 }
04414
04415
04416
04417
04418
04419 int ast_context_add_ignorepat(const char *con, const char *value, const char *registrar)
04420 {
04421 struct ast_context *c;
04422
04423 if (ast_lock_contexts()) {
04424 errno = EBUSY;
04425 return -1;
04426 }
04427
04428 c = ast_walk_contexts(NULL);
04429 while (c) {
04430 if (!strcmp(ast_get_context_name(c), con)) {
04431 int ret = ast_context_add_ignorepat2(c, value, registrar);
04432 ast_unlock_contexts();
04433 return ret;
04434 }
04435 c = ast_walk_contexts(c);
04436 }
04437
04438 ast_unlock_contexts();
04439 errno = ENOENT;
04440 return -1;
04441 }
04442
04443 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04444 {
04445 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04446 int length;
04447 length = sizeof(struct ast_ignorepat);
04448 length += strlen(value) + 1;
04449 ignorepat = malloc(length);
04450 if (!ignorepat) {
04451 ast_log(LOG_ERROR, "Out of memory\n");
04452 errno = ENOMEM;
04453 return -1;
04454 }
04455 memset(ignorepat, 0, length);
04456 strcpy(ignorepat->pattern, value);
04457 ignorepat->next = NULL;
04458 ignorepat->registrar = registrar;
04459 ast_mutex_lock(&con->lock);
04460 ignorepatc = con->ignorepats;
04461 while(ignorepatc) {
04462 ignorepatl = ignorepatc;
04463 if (!strcasecmp(ignorepatc->pattern, value)) {
04464
04465 ast_mutex_unlock(&con->lock);
04466 errno = EEXIST;
04467 return -1;
04468 }
04469 ignorepatc = ignorepatc->next;
04470 }
04471 if (ignorepatl)
04472 ignorepatl->next = ignorepat;
04473 else
04474 con->ignorepats = ignorepat;
04475 ast_mutex_unlock(&con->lock);
04476 return 0;
04477
04478 }
04479
04480 int ast_ignore_pattern(const char *context, const char *pattern)
04481 {
04482 struct ast_context *con;
04483 struct ast_ignorepat *pat;
04484
04485 con = ast_context_find(context);
04486 if (con) {
04487 pat = con->ignorepats;
04488 while (pat) {
04489 if (ast_extension_match(pat->pattern, pattern))
04490 return 1;
04491 pat = pat->next;
04492 }
04493 }
04494 return 0;
04495 }
04496
04497
04498
04499
04500
04501
04502 int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid,
04503 const char *application, void *data, void (*datad)(void *), const char *registrar)
04504 {
04505 struct ast_context *c;
04506
04507 if (ast_lock_contexts()) {
04508 errno = EBUSY;
04509 return -1;
04510 }
04511
04512 c = ast_walk_contexts(NULL);
04513 while (c) {
04514 if (!strcmp(context, ast_get_context_name(c))) {
04515 int ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
04516 application, data, datad, registrar);
04517 ast_unlock_contexts();
04518 return ret;
04519 }
04520 c = ast_walk_contexts(c);
04521 }
04522
04523 ast_unlock_contexts();
04524 errno = ENOENT;
04525 return -1;
04526 }
04527
04528 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04529 {
04530 if (!chan)
04531 return -1;
04532
04533 if (!ast_strlen_zero(context))
04534 ast_copy_string(chan->context, context, sizeof(chan->context));
04535 if (!ast_strlen_zero(exten))
04536 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
04537 if (priority > -1) {
04538 chan->priority = priority;
04539
04540 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
04541 chan->priority--;
04542 }
04543
04544 return 0;
04545 }
04546
04547 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04548 {
04549 int res = 0;
04550
04551 ast_mutex_lock(&chan->lock);
04552
04553 if (chan->pbx) {
04554
04555 ast_explicit_goto(chan, context, exten, priority);
04556 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
04557 } else {
04558
04559
04560
04561 struct ast_channel *tmpchan;
04562 tmpchan = ast_channel_alloc(0);
04563 if (tmpchan) {
04564 snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
04565 ast_setstate(tmpchan, chan->_state);
04566
04567 tmpchan->readformat = chan->readformat;
04568 tmpchan->writeformat = chan->writeformat;
04569
04570 ast_explicit_goto(tmpchan,
04571 (!ast_strlen_zero(context)) ? context : chan->context,
04572 (!ast_strlen_zero(exten)) ? exten : chan->exten,
04573 priority);
04574
04575
04576 ast_channel_masquerade(tmpchan, chan);
04577
04578
04579 ast_mutex_lock(&tmpchan->lock);
04580 ast_do_masquerade(tmpchan);
04581 ast_mutex_unlock(&tmpchan->lock);
04582
04583 if (ast_pbx_start(tmpchan)) {
04584 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
04585 ast_hangup(tmpchan);
04586 res = -1;
04587 }
04588 } else {
04589 res = -1;
04590 }
04591 }
04592 ast_mutex_unlock(&chan->lock);
04593 return res;
04594 }
04595
04596 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
04597 {
04598 struct ast_channel *chan;
04599 int res = -1;
04600
04601 chan = ast_get_channel_by_name_locked(channame);
04602 if (chan) {
04603 res = ast_async_goto(chan, context, exten, priority);
04604 ast_mutex_unlock(&chan->lock);
04605 }
04606 return res;
04607 }
04608
04609 static int ext_strncpy(char *dst, const char *src, int len)
04610 {
04611 int count=0;
04612
04613 while(*src && (count < len - 1)) {
04614 switch(*src) {
04615 case ' ':
04616
04617
04618
04619 break;
04620 default:
04621 *dst = *src;
04622 dst++;
04623 }
04624 src++;
04625 count++;
04626 }
04627 *dst = '\0';
04628
04629 return count;
04630 }
04631
04632 static void null_datad(void *foo)
04633 {
04634 }
04635
04636
04637
04638
04639
04640
04641 int ast_add_extension2(struct ast_context *con,
04642 int replace, const char *extension, int priority, const char *label, const char *callerid,
04643 const char *application, void *data, void (*datad)(void *),
04644 const char *registrar)
04645 {
04646
04647 #define LOG do { if (option_debug) {\
04648 if (tmp->matchcid) { \
04649 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
04650 } else { \
04651 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
04652 } \
04653 } else if (option_verbose > 2) { \
04654 if (tmp->matchcid) { \
04655 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
04656 } else { \
04657 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
04658 } \
04659 } } while(0)
04660
04661
04662
04663
04664
04665
04666
04667 struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
04668 int res;
04669 int length;
04670 char *p;
04671 char expand_buf[VAR_BUF_SIZE] = { 0, };
04672
04673
04674
04675
04676 ast_mutex_lock(&globalslock);
04677 if ((priority == PRIORITY_HINT) && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04678 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04679 application = expand_buf;
04680 }
04681 ast_mutex_unlock(&globalslock);
04682
04683 length = sizeof(struct ast_exten);
04684 length += strlen(extension) + 1;
04685 length += strlen(application) + 1;
04686 if (label)
04687 length += strlen(label) + 1;
04688 if (callerid)
04689 length += strlen(callerid) + 1;
04690 else
04691 length ++;
04692
04693
04694 if (datad == NULL)
04695 datad = null_datad;
04696 tmp = malloc(length);
04697 if (tmp) {
04698 memset(tmp, 0, length);
04699 p = tmp->stuff;
04700 if (label) {
04701 tmp->label = p;
04702 strcpy(tmp->label, label);
04703 p += strlen(label) + 1;
04704 }
04705 tmp->exten = p;
04706 p += ext_strncpy(tmp->exten, extension, strlen(extension) + 1) + 1;
04707 tmp->priority = priority;
04708 tmp->cidmatch = p;
04709 if (callerid) {
04710 p += ext_strncpy(tmp->cidmatch, callerid, strlen(callerid) + 1) + 1;
04711 tmp->matchcid = 1;
04712 } else {
04713 tmp->cidmatch[0] = '\0';
04714 tmp->matchcid = 0;
04715 p++;
04716 }
04717 tmp->app = p;
04718 strcpy(tmp->app, application);
04719 tmp->parent = con;
04720 tmp->data = data;
04721 tmp->datad = datad;
04722 tmp->registrar = registrar;
04723 tmp->peer = NULL;
04724 tmp->next = NULL;
04725 } else {
04726 ast_log(LOG_ERROR, "Out of memory\n");
04727 errno = ENOMEM;
04728 return -1;
04729 }
04730 if (ast_mutex_lock(&con->lock)) {
04731 free(tmp);
04732
04733 datad(data);
04734 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
04735 errno = EBUSY;
04736 return -1;
04737 }
04738 e = con->root;
04739 while(e) {
04740
04741 if ((e->exten[0] != '_') && (extension[0] == '_'))
04742 res = -1;
04743 else if ((e->exten[0] == '_') && (extension[0] != '_'))
04744 res = 1;
04745 else
04746 res= strcmp(e->exten, extension);
04747 if (!res) {
04748 if (!e->matchcid && !tmp->matchcid)
04749 res = 0;
04750 else if (tmp->matchcid && !e->matchcid)
04751 res = 1;
04752 else if (e->matchcid && !tmp->matchcid)
04753 res = -1;
04754 else
04755 res = strcasecmp(e->cidmatch, tmp->cidmatch);
04756 }
04757 if (res == 0) {
04758
04759
04760 while(e) {
04761 if (e->priority == tmp->priority) {
04762
04763
04764 if (replace) {
04765 if (ep) {
04766
04767 ep->peer = tmp;
04768 tmp->peer = e->peer;
04769 } else if (el) {
04770
04771 el->next = tmp;
04772 tmp->next = e->next;
04773 tmp->peer = e->peer;
04774 } else {
04775
04776 con->root = tmp;
04777 tmp->next = e->next;
04778 tmp->peer = e->peer;
04779 }
04780 if (tmp->priority == PRIORITY_HINT)
04781 ast_change_hint(e,tmp);
04782
04783 e->datad(e->data);
04784 free(e);
04785 ast_mutex_unlock(&con->lock);
04786 if (tmp->priority == PRIORITY_HINT)
04787 ast_change_hint(e, tmp);
04788
04789 LOG;
04790 return 0;
04791 } else {
04792 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04793 tmp->datad(tmp->data);
04794 free(tmp);
04795 ast_mutex_unlock(&con->lock);
04796 errno = EEXIST;
04797 return -1;
04798 }
04799 } else if (e->priority > tmp->priority) {
04800
04801 if (ep) {
04802
04803 ep->peer = tmp;
04804 tmp->peer = e;
04805 } else if (el) {
04806
04807 el->next = tmp;
04808 tmp->next = e->next;
04809 e->next = NULL;
04810 tmp->peer = e;
04811 } else {
04812
04813 tmp->next = con->root->next;
04814
04815 tmp->peer = con->root;
04816 con->root = tmp;
04817 }
04818 ast_mutex_unlock(&con->lock);
04819
04820
04821 if (tmp->priority == PRIORITY_HINT)
04822 ast_add_hint(tmp);
04823
04824 LOG;
04825 return 0;
04826 }
04827 ep = e;
04828 e = e->peer;
04829 }
04830
04831
04832 ep->peer = tmp;
04833 ast_mutex_unlock(&con->lock);
04834 if (tmp->priority == PRIORITY_HINT)
04835 ast_add_hint(tmp);
04836
04837
04838 LOG;
04839 return 0;
04840
04841 } else if (res > 0) {
04842
04843
04844 tmp->next = e;
04845 if (el) {
04846
04847 el->next = tmp;
04848 } else {
04849
04850 con->root = tmp;
04851 }
04852 ast_mutex_unlock(&con->lock);
04853 if (tmp->priority == PRIORITY_HINT)
04854 ast_add_hint(tmp);
04855
04856
04857 LOG;
04858 return 0;
04859 }
04860
04861 el = e;
04862 e = e->next;
04863 }
04864
04865 if (el)
04866 el->next = tmp;
04867 else
04868 con->root = tmp;
04869 ast_mutex_unlock(&con->lock);
04870 if (tmp->priority == PRIORITY_HINT)
04871 ast_add_hint(tmp);
04872 LOG;
04873 return 0;
04874 }
04875
04876 struct async_stat {
04877 pthread_t p;
04878 struct ast_channel *chan;
04879 char context[AST_MAX_CONTEXT];
04880 char exten[AST_MAX_EXTENSION];
04881 int priority;
04882 int timeout;
04883 char app[AST_MAX_EXTENSION];
04884 char appdata[1024];
04885 };
04886
04887 static void *async_wait(void *data)
04888 {
04889 struct async_stat *as = data;
04890 struct ast_channel *chan = as->chan;
04891 int timeout = as->timeout;
04892 int res;
04893 struct ast_frame *f;
04894 struct ast_app *app;
04895
04896 while(timeout && (chan->_state != AST_STATE_UP)) {
04897 res = ast_waitfor(chan, timeout);
04898 if (res < 1)
04899 break;
04900 if (timeout > -1)
04901 timeout = res;
04902 f = ast_read(chan);
04903 if (!f)
04904 break;
04905 if (f->frametype == AST_FRAME_CONTROL) {
04906 if ((f->subclass == AST_CONTROL_BUSY) ||
04907 (f->subclass == AST_CONTROL_CONGESTION) )
04908 break;
04909 }
04910 ast_frfree(f);
04911 }
04912 if (chan->_state == AST_STATE_UP) {
04913 if (!ast_strlen_zero(as->app)) {
04914 app = pbx_findapp(as->app);
04915 if (app) {
04916 if (option_verbose > 2)
04917 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04918 pbx_exec(chan, app, as->appdata, 1);
04919 } else
04920 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04921 } else {
04922 if (!ast_strlen_zero(as->context))
04923 ast_copy_string(chan->context, as->context, sizeof(chan->context));
04924 if (!ast_strlen_zero(as->exten))
04925 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
04926 if (as->priority > 0)
04927 chan->priority = as->priority;
04928
04929 if (ast_pbx_run(chan)) {
04930 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04931 } else {
04932
04933 chan = NULL;
04934 }
04935 }
04936
04937 }
04938 free(as);
04939 if (chan)
04940 ast_hangup(chan);
04941 return NULL;
04942 }
04943
04944
04945
04946
04947
04948
04949 int ast_pbx_outgoing_cdr_failed(void)
04950 {
04951
04952 struct ast_channel *chan = ast_channel_alloc(0);
04953 if(!chan) {
04954
04955 ast_log(LOG_WARNING, "Unable to allocate channel structure for CDR record\n");
04956 return -1;
04957 }
04958
04959 chan->cdr = ast_cdr_alloc();
04960
04961 if(!chan->cdr) {
04962
04963 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
04964 ast_channel_free(chan);
04965 return -1;
04966 }
04967
04968
04969 ast_cdr_init(chan->cdr, chan);
04970 ast_cdr_start(chan->cdr);
04971 ast_cdr_end(chan->cdr);
04972 ast_cdr_failed(chan->cdr);
04973 ast_cdr_detach(chan->cdr);
04974 ast_channel_free(chan);
04975
04976 return 0;
04977 }
04978
04979 int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
04980 {
04981 struct ast_channel *chan;
04982 struct async_stat *as;
04983 int res = -1, cdr_res = -1;
04984 struct outgoing_helper oh;
04985 pthread_attr_t attr;
04986
04987 if (sync) {
04988 LOAD_OH(oh);
04989 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
04990 if (channel) {
04991 *channel = chan;
04992 if (chan)
04993 ast_mutex_lock(&chan->lock);
04994 }
04995 if (chan) {
04996 if (chan->cdr) {
04997 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
04998 } else {
04999 chan->cdr = ast_cdr_alloc();
05000 if (!chan->cdr) {
05001
05002 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
05003 free(chan->pbx);
05004 res = -1;
05005 goto outgoing_exten_cleanup;
05006 }
05007
05008 ast_cdr_init(chan->cdr, chan);
05009 ast_cdr_start(chan->cdr);
05010 }
05011 if (chan->_state == AST_STATE_UP) {
05012 res = 0;
05013 if (option_verbose > 3)
05014 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05015
05016 if (sync > 1) {
05017 if (channel)
05018 ast_mutex_unlock(&chan->lock);
05019 if (ast_pbx_run(chan)) {
05020 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05021 if (channel)
05022 *channel = NULL;
05023 ast_hangup(chan);
05024 res = -1;
05025 }
05026 } else {
05027 if (ast_pbx_start(chan)) {
05028 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05029 if (channel) {
05030 *channel = NULL;
05031 ast_mutex_unlock(&chan->lock);
05032 }
05033 ast_hangup(chan);
05034 res = -1;
05035 }
05036 }
05037 } else {
05038 if (option_verbose > 3)
05039 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05040
05041 if(chan->cdr) {
05042
05043
05044 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05045 ast_cdr_failed(chan->cdr);
05046 }
05047
05048 if (channel) {
05049 *channel = NULL;
05050 ast_mutex_unlock(&chan->lock);
05051 }
05052 ast_hangup(chan);
05053 }
05054 }
05055
05056 if (res < 0) {
05057 if (*reason == 0) {
05058
05059 cdr_res = ast_pbx_outgoing_cdr_failed();
05060 if (cdr_res != 0) {
05061 res = cdr_res;
05062 goto outgoing_exten_cleanup;
05063 }
05064 }
05065
05066
05067
05068 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05069 chan = ast_channel_alloc(0);
05070 if (chan) {
05071 ast_copy_string(chan->name, "OutgoingSpoolFailed", sizeof(chan->name));
05072 if (!ast_strlen_zero(context))
05073 ast_copy_string(chan->context, context, sizeof(chan->context));
05074 ast_copy_string(chan->exten, "failed", sizeof(chan->exten));
05075 chan->priority = 1;
05076 ast_set_variables(chan, vars);
05077 if (account)
05078 ast_cdr_setaccount(chan, account);
05079 ast_pbx_run(chan);
05080 } else
05081 ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
05082 }
05083 }
05084 } else {
05085 as = malloc(sizeof(struct async_stat));
05086 if (!as) {
05087 res = -1;
05088 goto outgoing_exten_cleanup;
05089 }
05090 memset(as, 0, sizeof(struct async_stat));
05091 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05092 if (channel) {
05093 *channel = chan;
05094 if (chan)
05095 ast_mutex_lock(&chan->lock);
05096 }
05097 if (!chan) {
05098 free(as);
05099 res = -1;
05100 goto outgoing_exten_cleanup;
05101 }
05102 as->chan = chan;
05103 ast_copy_string(as->context, context, sizeof(as->context));
05104 ast_copy_string(as->exten, exten, sizeof(as->exten));
05105 as->priority = priority;
05106 as->timeout = timeout;
05107 ast_set_variables(chan, vars);
05108 if (account)
05109 ast_cdr_setaccount(chan, account);
05110 pthread_attr_init(&attr);
05111 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05112 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05113 ast_log(LOG_WARNING, "Failed to start async wait\n");
05114 free(as);
05115 if (channel) {
05116 *channel = NULL;
05117 ast_mutex_unlock(&chan->lock);
05118 }
05119 ast_hangup(chan);
05120 res = -1;
05121 goto outgoing_exten_cleanup;
05122 }
05123 res = 0;
05124 }
05125 outgoing_exten_cleanup:
05126 ast_variables_destroy(vars);
05127 return res;
05128 }
05129
05130 struct app_tmp {
05131 char app[256];
05132 char data[256];
05133 struct ast_channel *chan;
05134 pthread_t t;
05135 };
05136
05137 static void *ast_pbx_run_app(void *data)
05138 {
05139 struct app_tmp *tmp = data;
05140 struct ast_app *app;
05141 app = pbx_findapp(tmp->app);
05142 if (app) {
05143 if (option_verbose > 3)
05144 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05145 pbx_exec(tmp->chan, app, tmp->data, 1);
05146 } else
05147 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05148 ast_hangup(tmp->chan);
05149 free(tmp);
05150 return NULL;
05151 }
05152
05153 int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
05154 {
05155 struct ast_channel *chan;
05156 struct async_stat *as;
05157 struct app_tmp *tmp;
05158 int res = -1, cdr_res = -1;
05159 struct outgoing_helper oh;
05160 pthread_attr_t attr;
05161
05162 memset(&oh, 0, sizeof(oh));
05163 oh.vars = vars;
05164 oh.account = account;
05165
05166 if (locked_channel)
05167 *locked_channel = NULL;
05168 if (ast_strlen_zero(app)) {
05169 res = -1;
05170 goto outgoing_app_cleanup;
05171 }
05172 if (sync) {
05173 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05174 if (chan) {
05175 if (chan->cdr) {
05176 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
05177 } else {
05178 chan->cdr = ast_cdr_alloc();
05179 if(!chan->cdr) {
05180
05181 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
05182 free(chan->pbx);
05183 res = -1;
05184 goto outgoing_app_cleanup;
05185 }
05186
05187 ast_cdr_init(chan->cdr, chan);
05188 ast_cdr_start(chan->cdr);
05189 }
05190 ast_set_variables(chan, vars);
05191 if (account)
05192 ast_cdr_setaccount(chan, account);
05193 if (chan->_state == AST_STATE_UP) {
05194 res = 0;
05195 if (option_verbose > 3)
05196 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05197 tmp = malloc(sizeof(struct app_tmp));
05198 if (tmp) {
05199 memset(tmp, 0, sizeof(struct app_tmp));
05200 ast_copy_string(tmp->app, app, sizeof(tmp->app));
05201 if (appdata)
05202 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05203 tmp->chan = chan;
05204 if (sync > 1) {
05205 if (locked_channel)
05206 ast_mutex_unlock(&chan->lock);
05207 ast_pbx_run_app(tmp);
05208 } else {
05209 pthread_attr_init(&attr);
05210 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05211 if (locked_channel)
05212 ast_mutex_lock(&chan->lock);
05213 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05214 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05215 free(tmp);
05216 if (locked_channel)
05217 ast_mutex_unlock(&chan->lock);
05218 ast_hangup(chan);
05219 res = -1;
05220 } else {
05221 if (locked_channel)
05222 *locked_channel = chan;
05223 }
05224 }
05225 } else {
05226 ast_log(LOG_ERROR, "Out of memory :(\n");
05227 res = -1;
05228 }
05229 } else {
05230 if (option_verbose > 3)
05231 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05232 if (chan->cdr) {
05233
05234
05235 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05236 ast_cdr_failed(chan->cdr);
05237 }
05238 ast_hangup(chan);
05239 }
05240 }
05241
05242 if (res < 0) {
05243 if (*reason == 0) {
05244
05245 cdr_res = ast_pbx_outgoing_cdr_failed();
05246 if (cdr_res != 0) {
05247 res = cdr_res;
05248 goto outgoing_app_cleanup;
05249 }
05250 }
05251 }
05252
05253 } else {
05254 as = malloc(sizeof(struct async_stat));
05255 if (!as) {
05256 res = -1;
05257 goto outgoing_app_cleanup;
05258 }
05259 memset(as, 0, sizeof(struct async_stat));
05260 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05261 if (!chan) {
05262 free(as);
05263 res = -1;
05264 goto outgoing_app_cleanup;
05265 }
05266 as->chan = chan;
05267 ast_copy_string(as->app, app, sizeof(as->app));
05268 if (appdata)
05269 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
05270 as->timeout = timeout;
05271 ast_set_variables(chan, vars);
05272 if (account)
05273 ast_cdr_setaccount(chan, account);
05274
05275 pthread_attr_init(&attr);
05276 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05277 if (locked_channel)
05278 ast_mutex_lock(&chan->lock);
05279 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05280 ast_log(LOG_WARNING, "Failed to start async wait\n");
05281 free(as);
05282 if (locked_channel)
05283 ast_mutex_unlock(&chan->lock);
05284 ast_hangup(chan);
05285 res = -1;
05286 goto outgoing_app_cleanup;
05287 } else {
05288 if (locked_channel)
05289 *locked_channel = chan;
05290 }
05291 res = 0;
05292 }
05293 outgoing_app_cleanup:
05294 ast_variables_destroy(vars);
05295 return res;
05296 }
05297
05298 static void destroy_exten(struct ast_exten *e)
05299 {
05300 if (e->priority == PRIORITY_HINT)
05301 ast_remove_hint(e);
05302
05303 if (e->datad)
05304 e->datad(e->data);
05305 free(e);
05306 }
05307
05308 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05309 {
05310 struct ast_context *tmp, *tmpl=NULL;
05311 struct ast_include *tmpi, *tmpil= NULL;
05312 struct ast_sw *sw, *swl= NULL;
05313 struct ast_exten *e, *el, *en;
05314 struct ast_ignorepat *ipi, *ipl = NULL;
05315
05316 ast_mutex_lock(&conlock);
05317 tmp = contexts;
05318 while(tmp) {
05319 if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
05320 (!registrar || !strcasecmp(registrar, tmp->registrar))) {
05321
05322
05323 if (ast_mutex_lock(&tmp->lock)) {
05324 ast_log(LOG_WARNING, "Unable to lock context lock\n");
05325 return;
05326 }
05327 if (tmpl)
05328 tmpl->next = tmp->next;
05329 else
05330 contexts = tmp->next;
05331
05332
05333 ast_mutex_unlock(&tmp->lock);
05334 for (tmpi = tmp->includes; tmpi; ) {
05335
05336 tmpil = tmpi;
05337 tmpi = tmpi->next;
05338 free(tmpil);
05339 }
05340 for (ipi = tmp->ignorepats; ipi; ) {
05341
05342 ipl = ipi;
05343 ipi = ipi->next;
05344 free(ipl);
05345 }
05346 for (sw = tmp->alts; sw; ) {
05347
05348 swl = sw;
05349 sw = sw->next;
05350 free(swl);
05351 swl = sw;
05352 }
05353 for (e = tmp->root; e;) {
05354 for (en = e->peer; en;) {
05355 el = en;
05356 en = en->peer;
05357 destroy_exten(el);
05358 }
05359 el = e;
05360 e = e->next;
05361 destroy_exten(el);
05362 }
05363 ast_mutex_destroy(&tmp->lock);
05364 free(tmp);
05365 if (!con) {
05366
05367 tmp = contexts;
05368 tmpl = NULL;
05369 tmpil = NULL;
05370 continue;
05371 }
05372 ast_mutex_unlock(&conlock);
05373 return;
05374 }
05375 tmpl = tmp;
05376 tmp = tmp->next;
05377 }
05378 ast_mutex_unlock(&conlock);
05379 }
05380
05381 void ast_context_destroy(struct ast_context *con, const char *registrar)
05382 {
05383 __ast_context_destroy(con,registrar);
05384 }
05385
05386 static void wait_for_hangup(struct ast_channel *chan, void *data)
05387 {
05388 int res;
05389 struct ast_frame *f;
05390 int waittime;
05391
05392 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
05393 waittime = -1;
05394 if (waittime > -1) {
05395 ast_safe_sleep(chan, waittime * 1000);
05396 } else do {
05397 res = ast_waitfor(chan, -1);
05398 if (res < 0)
05399 return;
05400 f = ast_read(chan);
05401 if (f)
05402 ast_frfree(f);
05403 } while(f);
05404 }
05405
05406
05407
05408
05409 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05410 {
05411 ast_indicate(chan, AST_CONTROL_PROGRESS);
05412 return 0;
05413 }
05414
05415
05416
05417
05418 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05419 {
05420 ast_indicate(chan, AST_CONTROL_RINGING);
05421 return 0;
05422 }
05423
05424
05425
05426
05427 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05428 {
05429 ast_indicate(chan, AST_CONTROL_BUSY);
05430 ast_setstate(chan, AST_STATE_BUSY);
05431 wait_for_hangup(chan, data);
05432 return -1;
05433 }
05434
05435
05436
05437
05438 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
05439 {
05440 ast_indicate(chan, AST_CONTROL_CONGESTION);
05441 ast_setstate(chan, AST_STATE_BUSY);
05442 wait_for_hangup(chan, data);
05443 return -1;
05444 }
05445
05446
05447
05448
05449 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05450 {
05451 int delay = 0;
05452 int res;
05453
05454 if (chan->_state == AST_STATE_UP)
05455 delay = 0;
05456 else if (!ast_strlen_zero(data))
05457 delay = atoi(data);
05458
05459 res = ast_answer(chan);
05460 if (res)
05461 return res;
05462
05463 if (delay)
05464 res = ast_safe_sleep(chan, delay);
05465
05466 return res;
05467 }
05468
05469
05470
05471
05472 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
05473 {
05474 static int deprecation_warning = 0;
05475
05476 if (!deprecation_warning) {
05477 ast_log(LOG_WARNING, "SetLanguage is deprecated, please use Set(LANGUAGE()=language) instead.\n");
05478 deprecation_warning = 1;
05479 }
05480
05481
05482 if (!ast_strlen_zero(data))
05483 ast_copy_string(chan->language, data, sizeof(chan->language));
05484
05485 return 0;
05486 }
05487
05488 AST_APP_OPTIONS(resetcdr_opts, {
05489 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05490 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05491 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05492 });
05493
05494
05495
05496
05497 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05498 {
05499 char *args;
05500 struct ast_flags flags = { 0 };
05501
05502 if (!ast_strlen_zero(data)) {
05503 args = ast_strdupa(data);
05504 if (!args) {
05505 ast_log(LOG_ERROR, "Out of memory!\n");
05506 return -1;
05507 }
05508 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05509 }
05510
05511 ast_cdr_reset(chan->cdr, &flags);
05512
05513 return 0;
05514 }
05515
05516
05517
05518
05519 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
05520 {
05521
05522 if (data)
05523 ast_cdr_setaccount(chan, (char *)data);
05524 else
05525 ast_cdr_setaccount(chan, "");
05526 return 0;
05527 }
05528
05529
05530
05531
05532 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05533 {
05534
05535 if (data)
05536 ast_cdr_setamaflags(chan, (char *)data);
05537 else
05538 ast_cdr_setamaflags(chan, "");
05539 return 0;
05540 }
05541
05542
05543
05544
05545 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05546 {
05547
05548 if (!chan->hangupcause)
05549 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05550 return -1;
05551 }
05552
05553
05554
05555
05556 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05557 {
05558 int res=0;
05559 char *s, *ts;
05560 struct ast_timing timing;
05561
05562 if (ast_strlen_zero(data)) {
05563 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05564 return -1;
05565 }
05566
05567 if ((s = ast_strdupa((char *) data))) {
05568 ts = s;
05569
05570
05571 strsep(&ts,"?");
05572
05573
05574 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05575 res = pbx_builtin_goto(chan, (void *)ts);
05576 } else {
05577 ast_log(LOG_ERROR, "Memory Error!\n");
05578 }
05579 return res;
05580 }
05581
05582
05583
05584
05585 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05586 {
05587 int res = 0;
05588 char *ptr1, *ptr2;
05589 struct ast_timing timing;
05590 struct ast_app *app;
05591 const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05592
05593 if (ast_strlen_zero(data)) {
05594 ast_log(LOG_WARNING, "%s\n", usage);
05595 return -1;
05596 }
05597
05598 ptr1 = ast_strdupa(data);
05599
05600 if (!ptr1) {
05601 ast_log(LOG_ERROR, "Out of Memory!\n");
05602 return -1;
05603 }
05604
05605 ptr2 = ptr1;
05606
05607 strsep(&ptr2,"?");
05608 if(!ast_build_timing(&timing, ptr1)) {
05609 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", ptr1, usage);
05610 res = -1;
05611 }
05612
05613 if (!res && ast_check_timing(&timing)) {
05614 if (!ptr2) {
05615 ast_log(LOG_WARNING, "%s\n", usage);
05616 }
05617
05618
05619
05620 if((ptr1 = strchr(ptr2, '|'))) {
05621 *ptr1 = '\0';
05622 ptr1++;
05623 }
05624
05625 if ((app = pbx_findapp(ptr2))) {
05626 res = pbx_exec(chan, app, ptr1 ? ptr1 : "", 1);
05627 } else {
05628 ast_log(LOG_WARNING, "Cannot locate application %s\n", ptr2);
05629 res = -1;
05630 }
05631 }
05632
05633 return res;
05634 }
05635
05636
05637
05638
05639 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05640 {
05641 int ms;
05642
05643
05644 if (data && atof((char *)data)) {
05645 ms = atof((char *)data) * 1000;
05646 return ast_safe_sleep(chan, ms);
05647 }
05648 return 0;
05649 }
05650
05651
05652
05653
05654 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05655 {
05656 int ms, res, argc;
05657 char *args;
05658 char *argv[2];
05659 char *options = NULL;
05660 char *timeout = NULL;
05661 struct ast_flags flags = {0};
05662 char *opts[1] = { NULL };
05663
05664 args = ast_strdupa(data);
05665
05666 if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
05667 if (argc > 0) {
05668 timeout = argv[0];
05669 if (argc > 1)
05670 options = argv[1];
05671 }
05672 }
05673
05674 if (options)
05675 ast_app_parse_options(waitexten_opts, &flags, opts, options);
05676
05677 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05678 ast_moh_start(chan, opts[0]);
05679
05680
05681 if (timeout && atof((char *)timeout))
05682 ms = atof((char *)timeout) * 1000;
05683 else if (chan->pbx)
05684 ms = chan->pbx->rtimeout * 1000;
05685 else
05686 ms = 10000;
05687 res = ast_waitfordigit(chan, ms);
05688 if (!res) {
05689 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05690 if (option_verbose > 2)
05691 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05692 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05693 if (option_verbose > 2)
05694 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05695 ast_copy_string(chan->exten, "t", sizeof(chan->exten));
05696 chan->priority = 0;
05697 } else {
05698 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05699 res = -1;
05700 }
05701 }
05702
05703 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05704 ast_moh_stop(chan);
05705
05706 return res;
05707 }
05708
05709
05710
05711
05712 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05713 {
05714 int res = 0;
05715 int argc;
05716 char *parse;
05717 char *argv[4];
05718 char *options = NULL;
05719 char *filename = NULL;
05720 char *front = NULL, *back = NULL;
05721 char *lang = NULL;
05722 char *context = NULL;
05723 struct ast_flags flags = {0};
05724
05725 parse = ast_strdupa(data);
05726
05727 if ((argc = ast_app_separate_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
05728 switch (argc) {
05729 case 4:
05730 context = argv[3];
05731 case 3:
05732 lang = argv[2];
05733 case 2:
05734 options = argv[1];
05735 case 1:
05736 filename = argv[0];
05737 break;
05738 default:
05739 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05740 break;
05741 }
05742 }
05743
05744 if (!lang)
05745 lang = chan->language;
05746
05747 if (!context)
05748 context = chan->context;
05749
05750 if (options) {
05751 if (!strcasecmp(options, "skip"))
05752 flags.flags = BACKGROUND_SKIP;
05753 else if (!strcasecmp(options, "noanswer"))
05754 flags.flags = BACKGROUND_NOANSWER;
05755 else
05756 ast_app_parse_options(background_opts, &flags, NULL, options);
05757 }
05758
05759
05760 if (chan->_state != AST_STATE_UP) {
05761 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05762 return 0;
05763 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05764 res = ast_answer(chan);
05765 }
05766 }
05767
05768 if (!res) {
05769
05770 ast_stopstream(chan);
05771
05772 front = filename;
05773 while(!res && front) {
05774 if((back = strchr(front, '&'))) {
05775 *back = '\0';
05776 back++;
05777 }
05778 res = ast_streamfile(chan, front, lang);
05779 if (!res) {
05780 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05781 res = ast_waitstream(chan, "");
05782 } else {
05783 if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05784 res = ast_waitstream_exten(chan, context);
05785 } else {
05786 res = ast_waitstream(chan, AST_DIGIT_ANY);
05787 }
05788 }
05789 ast_stopstream(chan);
05790 } else {
05791 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05792 res = 0;
05793 break;
05794 }
05795 front = back;
05796 }
05797 }
05798 if (context != chan->context && res) {
05799 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05800 ast_copy_string(chan->context, context, sizeof(chan->context));
05801 chan->priority = 0;
05802 return 0;
05803 } else {
05804 return res;
05805 }
05806 }
05807
05808
05809
05810
05811
05812 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
05813 {
05814 static int deprecation_warning = 0;
05815 int x = atoi((char *) data);
05816
05817 if (!deprecation_warning) {
05818 ast_log(LOG_WARNING, "AbsoluteTimeout is deprecated, please use Set(TIMEOUT(absolute)=timeout) instead.\n");
05819 deprecation_warning = 1;
05820 }
05821
05822
05823 ast_channel_setwhentohangup(chan,x);
05824 if (option_verbose > 2)
05825 ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
05826 return 0;
05827 }
05828
05829
05830
05831
05832
05833 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
05834 {
05835 static int deprecation_warning = 0;
05836
05837 if (!deprecation_warning) {
05838 ast_log(LOG_WARNING, "ResponseTimeout is deprecated, please use Set(TIMEOUT(response)=timeout) instead.\n");
05839 deprecation_warning = 1;
05840 }
05841
05842
05843 if (!chan->pbx)
05844 return 0;
05845
05846
05847 chan->pbx->rtimeout = atoi((char *)data);
05848 if (option_verbose > 2)
05849 ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
05850 return 0;
05851 }
05852
05853
05854
05855
05856
05857 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
05858 {
05859 static int deprecation_warning = 0;
05860
05861 if (!deprecation_warning) {
05862 ast_log(LOG_WARNING, "DigitTimeout is deprecated, please use Set(TIMEOUT(digit)=timeout) instead.\n");
05863 deprecation_warning = 1;
05864 }
05865
05866
05867 if (!chan->pbx)
05868 return 0;
05869
05870
05871 chan->pbx->dtimeout = atoi((char *)data);
05872 if (option_verbose > 2)
05873 ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
05874 return 0;
05875 }
05876
05877
05878
05879
05880 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05881 {
05882 int res;
05883 res = ast_parseable_goto(chan, (const char *) data);
05884 if (!res && (option_verbose > 2))
05885 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05886 return res;
05887 }
05888
05889
05890 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05891 {
05892 struct ast_var_t *variables;
05893 char *var, *val;
05894 int total = 0;
05895
05896 if (!chan)
05897 return 0;
05898
05899 memset(buf, 0, size);
05900
05901 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05902 if(variables &&
05903 (var=ast_var_name(variables)) && (val=ast_var_value(variables)) &&
05904 !ast_strlen_zero(var) && !ast_strlen_zero(val)) {
05905 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05906 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05907 break;
05908 } else
05909 total++;
05910 } else
05911 break;
05912 }
05913
05914 return total;
05915 }
05916
05917 char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05918 {
05919 struct ast_var_t *variables;
05920 char *ret = NULL;
05921 int i;
05922 struct varshead *places[2] = { NULL, &globals };
05923
05924 if (!name)
05925 return NULL;
05926 if (chan)
05927 places[0] = &chan->varshead;
05928
05929 for (i = 0; i < 2; i++) {
05930 if (!places[i])
05931 continue;
05932 if (places[i] == &globals)
05933 ast_mutex_lock(&globalslock);
05934 AST_LIST_TRAVERSE(places[i], variables, entries) {
05935 if (!strcmp(name, ast_var_name(variables))) {
05936 ret = ast_var_value(variables);
05937 break;
05938 }
05939 }
05940 if (places[i] == &globals)
05941 ast_mutex_unlock(&globalslock);
05942 if (ret)
05943 break;
05944 }
05945
05946 return ret;
05947 }
05948
05949 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05950 {
05951 struct ast_var_t *newvariable;
05952 struct varshead *headp;
05953
05954 if (name[strlen(name)-1] == ')') {
05955 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05956 return ast_func_write(chan, name, value);
05957 }
05958
05959 headp = (chan) ? &chan->varshead : &globals;
05960
05961 if (value) {
05962 if ((option_verbose > 1) && (headp == &globals))
05963 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05964 newvariable = ast_var_assign(name, value);
05965 if (headp == &globals)
05966 ast_mutex_lock(&globalslock);
05967 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05968 if (headp == &globals)
05969 ast_mutex_unlock(&globalslock);
05970 }
05971 }
05972
05973 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
05974 {
05975 struct ast_var_t *newvariable;
05976 struct varshead *headp;
05977 const char *nametail = name;
05978
05979 if (name[strlen(name)-1] == ')')
05980 return ast_func_write(chan, name, value);
05981
05982 headp = (chan) ? &chan->varshead : &globals;
05983
05984
05985 if (*nametail == '_') {
05986 nametail++;
05987 if (*nametail == '_')
05988 nametail++;
05989 }
05990
05991 if (headp == &globals)
05992 ast_mutex_lock(&globalslock);
05993 AST_LIST_TRAVERSE (headp, newvariable, entries) {
05994 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
05995
05996 AST_LIST_REMOVE(headp, newvariable, entries);
05997 ast_var_delete(newvariable);
05998 break;
05999 }
06000 }
06001
06002 if (value) {
06003 if ((option_verbose > 1) && (headp == &globals))
06004 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
06005 newvariable = ast_var_assign(name, value);
06006 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
06007 }
06008
06009 if (headp == &globals)
06010 ast_mutex_unlock(&globalslock);
06011 }
06012
06013 int pbx_builtin_setvar_old(struct ast_channel *chan, void *data)
06014 {
06015 static int deprecation_warning = 0;
06016
06017 if (!deprecation_warning) {
06018 ast_log(LOG_WARNING, "SetVar is deprecated, please use Set instead.\n");
06019 deprecation_warning = 1;
06020 }
06021
06022 return pbx_builtin_setvar(chan, data);
06023 }
06024
06025 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
06026 {
06027 char *name, *value, *mydata;
06028 int argc;
06029 char *argv[24];
06030 int global = 0;
06031 int x;
06032
06033 if (ast_strlen_zero(data)) {
06034 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
06035 return 0;
06036 }
06037
06038 mydata = ast_strdupa(data);
06039 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
06040
06041
06042 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
06043 argc--;
06044 if (strchr(argv[argc], 'g'))
06045 global = 1;
06046 }
06047
06048 for (x = 0; x < argc; x++) {
06049 name = argv[x];
06050 if ((value = strchr(name, '='))) {
06051 *value = '\0';
06052 value++;
06053 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
06054 } else
06055 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
06056 }
06057
06058 return(0);
06059 }
06060
06061 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
06062 {
06063 char *name;
06064 char *value;
06065 char *stringp=NULL;
06066 char *channel;
06067 struct ast_channel *chan2;
06068 char tmp[VAR_BUF_SIZE]="";
06069 char *s;
06070
06071 if (ast_strlen_zero(data)) {
06072 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06073 return 0;
06074 }
06075
06076 stringp = ast_strdupa(data);
06077 name = strsep(&stringp,"=");
06078 channel = strsep(&stringp,"|");
06079 value = strsep(&stringp,"\0");
06080 if (channel && value && name) {
06081 chan2 = ast_get_channel_by_name_locked(channel);
06082 if (chan2) {
06083 s = alloca(strlen(value) + 4);
06084 if (s) {
06085 sprintf(s, "${%s}", value);
06086 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
06087 }
06088 ast_mutex_unlock(&chan2->lock);
06089 }
06090 pbx_builtin_setvar_helper(chan, name, tmp);
06091 }
06092
06093 return(0);
06094 }
06095
06096 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
06097 {
06098 char *name;
06099 char *value;
06100 char *stringp = NULL;
06101
06102 if (ast_strlen_zero(data)) {
06103 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06104 return 0;
06105 }
06106
06107 stringp = data;
06108 name = strsep(&stringp, "=");
06109 value = strsep(&stringp, "\0");
06110
06111 pbx_builtin_setvar_helper(NULL, name, value);
06112
06113 return(0);
06114 }
06115
06116 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
06117 {
06118 return 0;
06119 }
06120
06121
06122 void pbx_builtin_clear_globals(void)
06123 {
06124 struct ast_var_t *vardata;
06125
06126 ast_mutex_lock(&globalslock);
06127 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
06128 ast_var_delete(vardata);
06129 ast_mutex_unlock(&globalslock);
06130 }
06131
06132 int pbx_checkcondition(char *condition)
06133 {
06134 if (condition) {
06135 if (*condition == '\0') {
06136
06137 return 0;
06138 } else if (*condition >= '0' && *condition <= '9') {
06139
06140 return atoi(condition);
06141 } else {
06142
06143 return 1;
06144 }
06145 } else {
06146
06147 return 0;
06148 }
06149 }
06150
06151 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
06152 {
06153 char *condition, *branch1, *branch2, *branch;
06154 char *s;
06155 int rc;
06156 char *stringp=NULL;
06157
06158 if (ast_strlen_zero(data)) {
06159 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
06160 return 0;
06161 }
06162
06163 s = ast_strdupa(data);
06164 stringp = s;
06165 condition = strsep(&stringp,"?");
06166 branch1 = strsep(&stringp,":");
06167 branch2 = strsep(&stringp,"");
06168 branch = pbx_checkcondition(condition) ? branch1 : branch2;
06169
06170 if (ast_strlen_zero(branch)) {
06171 ast_log(LOG_DEBUG, "Not taking any branch\n");
06172 return 0;
06173 }
06174
06175 rc = pbx_builtin_goto(chan, branch);
06176
06177 return rc;
06178 }
06179
06180 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
06181 {
06182 int res = 0;
06183 char tmp[256];
06184 char *number = (char *) NULL;
06185 char *options = (char *) NULL;
06186
06187
06188 if (ast_strlen_zero(data)) {
06189 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06190 return -1;
06191 }
06192 ast_copy_string(tmp, (char *) data, sizeof(tmp));
06193 number=tmp;
06194 strsep(&number, "|");
06195 options = strsep(&number, "|");
06196 if (options) {
06197 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06198 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06199 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06200 return -1;
06201 }
06202 }
06203 return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
06204 }
06205
06206 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06207 {
06208 int res = 0;
06209
06210 if (data)
06211 res = ast_say_digit_str(chan, (char *)data, "", chan->language);
06212 return res;
06213 }
06214
06215 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06216 {
06217 int res = 0;
06218
06219 if (data)
06220 res = ast_say_character_str(chan, (char *)data, "", chan->language);
06221 return res;
06222 }
06223
06224 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06225 {
06226 int res = 0;
06227
06228 if (data)
06229 res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
06230 return res;
06231 }
06232
06233 int load_pbx(void)
06234 {
06235 int x;
06236
06237
06238 if (option_verbose) {
06239 ast_verbose( "Asterisk PBX Core Initializing\n");
06240 ast_verbose( "Registering builtin applications:\n");
06241 }
06242 AST_LIST_HEAD_INIT_NOLOCK(&globals);
06243 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
06244
06245
06246 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06247 if (option_verbose)
06248 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06249 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06250 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06251 return -1;
06252 }
06253 }
06254 return 0;
06255 }
06256
06257
06258
06259
06260 int ast_lock_contexts()
06261 {
06262 return ast_mutex_lock(&conlock);
06263 }
06264
06265 int ast_unlock_contexts()
06266 {
06267 return ast_mutex_unlock(&conlock);
06268 }
06269
06270
06271
06272
06273 int ast_lock_context(struct ast_context *con)
06274 {
06275 return ast_mutex_lock(&con->lock);
06276 }
06277
06278 int ast_unlock_context(struct ast_context *con)
06279 {
06280 return ast_mutex_unlock(&con->lock);
06281 }
06282
06283
06284
06285
06286 const char *ast_get_context_name(struct ast_context *con)
06287 {
06288 return con ? con->name : NULL;
06289 }
06290
06291 const char *ast_get_extension_name(struct ast_exten *exten)
06292 {
06293 return exten ? exten->exten : NULL;
06294 }
06295
06296 const char *ast_get_extension_label(struct ast_exten *exten)
06297 {
06298 return exten ? exten->label : NULL;
06299 }
06300
06301 const char *ast_get_include_name(struct ast_include *inc)
06302 {
06303 return inc ? inc->name : NULL;
06304 }
06305
06306 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06307 {
06308 return ip ? ip->pattern : NULL;
06309 }
06310
06311 int ast_get_extension_priority(struct ast_exten *exten)
06312 {
06313 return exten ? exten->priority : -1;
06314 }
06315
06316
06317
06318
06319 const char *ast_get_context_registrar(struct ast_context *c)
06320 {
06321 return c ? c->registrar : NULL;
06322 }
06323
06324 const char *ast_get_extension_registrar(struct ast_exten *e)
06325 {
06326 return e ? e->registrar : NULL;
06327 }
06328
06329 const char *ast_get_include_registrar(struct ast_include *i)
06330 {
06331 return i ? i->registrar : NULL;
06332 }
06333
06334 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06335 {
06336 return ip ? ip->registrar : NULL;
06337 }
06338
06339 int ast_get_extension_matchcid(struct ast_exten *e)
06340 {
06341 return e ? e->matchcid : 0;
06342 }
06343
06344 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06345 {
06346 return e ? e->cidmatch : NULL;
06347 }
06348
06349 const char *ast_get_extension_app(struct ast_exten *e)
06350 {
06351 return e ? e->app : NULL;
06352 }
06353
06354 void *ast_get_extension_app_data(struct ast_exten *e)
06355 {
06356 return e ? e->data : NULL;
06357 }
06358
06359 const char *ast_get_switch_name(struct ast_sw *sw)
06360 {
06361 return sw ? sw->name : NULL;
06362 }
06363
06364 const char *ast_get_switch_data(struct ast_sw *sw)
06365 {
06366 return sw ? sw->data : NULL;
06367 }
06368
06369 const char *ast_get_switch_registrar(struct ast_sw *sw)
06370 {
06371 return sw ? sw->registrar : NULL;
06372 }
06373
06374
06375
06376
06377 struct ast_context *ast_walk_contexts(struct ast_context *con)
06378 {
06379 if (!con)
06380 return contexts;
06381 else
06382 return con->next;
06383 }
06384
06385 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06386 struct ast_exten *exten)
06387 {
06388 if (!exten)
06389 return con ? con->root : NULL;
06390 else
06391 return exten->next;
06392 }
06393
06394 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06395 struct ast_sw *sw)
06396 {
06397 if (!sw)
06398 return con ? con->alts : NULL;
06399 else
06400 return sw->next;
06401 }
06402
06403 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06404 struct ast_exten *priority)
06405 {
06406 if (!priority)
06407 return exten;
06408 else
06409 return priority->peer;
06410 }
06411
06412 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06413 struct ast_include *inc)
06414 {
06415 if (!inc)
06416 return con ? con->includes : NULL;
06417 else
06418 return inc->next;
06419 }
06420
06421 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06422 struct ast_ignorepat *ip)
06423 {
06424 if (!ip)
06425 return con ? con->ignorepats : NULL;
06426 else
06427 return ip->next;
06428 }
06429
06430 int ast_context_verify_includes(struct ast_context *con)
06431 {
06432 struct ast_include *inc;
06433 int res = 0;
06434
06435 for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
06436 if (!ast_context_find(inc->rname)) {
06437 res = -1;
06438 ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
06439 ast_get_context_name(con), inc->rname);
06440 }
06441 return res;
06442 }
06443
06444
06445 static int __ast_goto_if_exists(struct ast_channel *chan, char *context, char *exten, int priority, int async)
06446 {
06447 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06448
06449 if (!chan)
06450 return -2;
06451
06452 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06453 if (ast_exists_extension(chan, context ? context : chan->context,
06454 exten ? exten : chan->exten, priority,
06455 chan->cid.cid_num))
06456 return goto_func(chan, context ? context : chan->context,
06457 exten ? exten : chan->exten, priority);
06458 else
06459 return -3;
06460 }
06461
06462 int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
06463 return __ast_goto_if_exists(chan, context, exten, priority, 0);
06464 }
06465
06466 int ast_async_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
06467 return __ast_goto_if_exists(chan, context, exten, priority, 1);
06468 }
06469
06470 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06471 {
06472 char *s;
06473 char *exten, *pri, *context;
06474 char *stringp=NULL;
06475 int ipri;
06476 int mode = 0;
06477
06478 if (ast_strlen_zero(goto_string)) {
06479 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06480 return -1;
06481 }
06482 s = ast_strdupa(goto_string);
06483 stringp=s;
06484 context = strsep(&stringp, "|");
06485 exten = strsep(&stringp, "|");
06486 if (!exten) {
06487
06488 pri = context;
06489 exten = NULL;
06490 context = NULL;
06491 } else {
06492 pri = strsep(&stringp, "|");
06493 if (!pri) {
06494
06495 pri = exten;
06496 exten = context;
06497 context = NULL;
06498 }
06499 }
06500 if (*pri == '+') {
06501 mode = 1;
06502 pri++;
06503 } else if (*pri == '-') {
06504 mode = -1;
06505 pri++;
06506 }
06507 if (sscanf(pri, "%d", &ipri) != 1) {
06508 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten,
06509 pri, chan->cid.cid_num)) < 1) {
06510 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06511 return -1;
06512 } else
06513 mode = 0;
06514 }
06515
06516
06517 if (exten && !strcasecmp(exten, "BYEXTENSION"))
06518 exten = NULL;
06519
06520 if (mode)
06521 ipri = chan->priority + (ipri * mode);
06522
06523 ast_explicit_goto(chan, context, exten, ipri);
06524 ast_cdr_update(chan);
06525 return 0;
06526
06527 }