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