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: 43800 $")
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 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 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 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 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 } \
04657 if (option_verbose > 2) { \
04658 if (tmp->matchcid) { \
04659 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
04660 } else { \
04661 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
04662 } \
04663 } } while(0)
04664
04665
04666
04667
04668
04669
04670
04671 struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
04672 int res;
04673 int length;
04674 char *p;
04675 char expand_buf[VAR_BUF_SIZE] = { 0, };
04676
04677
04678
04679
04680 ast_mutex_lock(&globalslock);
04681 if ((priority == PRIORITY_HINT) && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04682 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04683 application = expand_buf;
04684 }
04685 ast_mutex_unlock(&globalslock);
04686
04687 length = sizeof(struct ast_exten);
04688 length += strlen(extension) + 1;
04689 length += strlen(application) + 1;
04690 if (label)
04691 length += strlen(label) + 1;
04692 if (callerid)
04693 length += strlen(callerid) + 1;
04694 else
04695 length ++;
04696
04697
04698 if (datad == NULL)
04699 datad = null_datad;
04700 tmp = malloc(length);
04701 if (tmp) {
04702 memset(tmp, 0, length);
04703 p = tmp->stuff;
04704 if (label) {
04705 tmp->label = p;
04706 strcpy(tmp->label, label);
04707 p += strlen(label) + 1;
04708 }
04709 tmp->exten = p;
04710 p += ext_strncpy(tmp->exten, extension, strlen(extension) + 1) + 1;
04711 tmp->priority = priority;
04712 tmp->cidmatch = p;
04713 if (callerid) {
04714 p += ext_strncpy(tmp->cidmatch, callerid, strlen(callerid) + 1) + 1;
04715 tmp->matchcid = 1;
04716 } else {
04717 tmp->cidmatch[0] = '\0';
04718 tmp->matchcid = 0;
04719 p++;
04720 }
04721 tmp->app = p;
04722 strcpy(tmp->app, application);
04723 tmp->parent = con;
04724 tmp->data = data;
04725 tmp->datad = datad;
04726 tmp->registrar = registrar;
04727 tmp->peer = NULL;
04728 tmp->next = NULL;
04729 } else {
04730 ast_log(LOG_ERROR, "Out of memory\n");
04731 errno = ENOMEM;
04732 return -1;
04733 }
04734 if (ast_mutex_lock(&con->lock)) {
04735 free(tmp);
04736
04737 datad(data);
04738 ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
04739 errno = EBUSY;
04740 return -1;
04741 }
04742 e = con->root;
04743 while(e) {
04744
04745 if ((e->exten[0] != '_') && (extension[0] == '_'))
04746 res = -1;
04747 else if ((e->exten[0] == '_') && (extension[0] != '_'))
04748 res = 1;
04749 else
04750 res= strcmp(e->exten, extension);
04751 if (!res) {
04752 if (!e->matchcid && !tmp->matchcid)
04753 res = 0;
04754 else if (tmp->matchcid && !e->matchcid)
04755 res = 1;
04756 else if (e->matchcid && !tmp->matchcid)
04757 res = -1;
04758 else
04759 res = strcasecmp(e->cidmatch, tmp->cidmatch);
04760 }
04761 if (res == 0) {
04762
04763
04764 while(e) {
04765 if (e->priority == tmp->priority) {
04766
04767
04768 if (replace) {
04769 if (ep) {
04770
04771 ep->peer = tmp;
04772 tmp->peer = e->peer;
04773 } else if (el) {
04774
04775 el->next = tmp;
04776 tmp->next = e->next;
04777 tmp->peer = e->peer;
04778 } else {
04779
04780 con->root = tmp;
04781 tmp->next = e->next;
04782 tmp->peer = e->peer;
04783 }
04784 if (tmp->priority == PRIORITY_HINT)
04785 ast_change_hint(e,tmp);
04786
04787 e->datad(e->data);
04788 free(e);
04789 ast_mutex_unlock(&con->lock);
04790 if (tmp->priority == PRIORITY_HINT)
04791 ast_change_hint(e, tmp);
04792
04793 LOG;
04794 return 0;
04795 } else {
04796 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04797 tmp->datad(tmp->data);
04798 free(tmp);
04799 ast_mutex_unlock(&con->lock);
04800 errno = EEXIST;
04801 return -1;
04802 }
04803 } else if (e->priority > tmp->priority) {
04804
04805 if (ep) {
04806
04807 ep->peer = tmp;
04808 tmp->peer = e;
04809 } else if (el) {
04810
04811 el->next = tmp;
04812 tmp->next = e->next;
04813 e->next = NULL;
04814 tmp->peer = e;
04815 } else {
04816
04817 tmp->next = con->root->next;
04818
04819 tmp->peer = con->root;
04820 con->root = tmp;
04821 }
04822 ast_mutex_unlock(&con->lock);
04823
04824
04825 if (tmp->priority == PRIORITY_HINT)
04826 ast_add_hint(tmp);
04827
04828 LOG;
04829 return 0;
04830 }
04831 ep = e;
04832 e = e->peer;
04833 }
04834
04835
04836 ep->peer = tmp;
04837 ast_mutex_unlock(&con->lock);
04838 if (tmp->priority == PRIORITY_HINT)
04839 ast_add_hint(tmp);
04840
04841
04842 LOG;
04843 return 0;
04844
04845 } else if (res > 0) {
04846
04847
04848 tmp->next = e;
04849 if (el) {
04850
04851 el->next = tmp;
04852 } else {
04853
04854 con->root = tmp;
04855 }
04856 ast_mutex_unlock(&con->lock);
04857 if (tmp->priority == PRIORITY_HINT)
04858 ast_add_hint(tmp);
04859
04860
04861 LOG;
04862 return 0;
04863 }
04864
04865 el = e;
04866 e = e->next;
04867 }
04868
04869 if (el)
04870 el->next = tmp;
04871 else
04872 con->root = tmp;
04873 ast_mutex_unlock(&con->lock);
04874 if (tmp->priority == PRIORITY_HINT)
04875 ast_add_hint(tmp);
04876 LOG;
04877 return 0;
04878 }
04879
04880 struct async_stat {
04881 pthread_t p;
04882 struct ast_channel *chan;
04883 char context[AST_MAX_CONTEXT];
04884 char exten[AST_MAX_EXTENSION];
04885 int priority;
04886 int timeout;
04887 char app[AST_MAX_EXTENSION];
04888 char appdata[1024];
04889 };
04890
04891 static void *async_wait(void *data)
04892 {
04893 struct async_stat *as = data;
04894 struct ast_channel *chan = as->chan;
04895 int timeout = as->timeout;
04896 int res;
04897 struct ast_frame *f;
04898 struct ast_app *app;
04899
04900 while(timeout && (chan->_state != AST_STATE_UP)) {
04901 res = ast_waitfor(chan, timeout);
04902 if (res < 1)
04903 break;
04904 if (timeout > -1)
04905 timeout = res;
04906 f = ast_read(chan);
04907 if (!f)
04908 break;
04909 if (f->frametype == AST_FRAME_CONTROL) {
04910 if ((f->subclass == AST_CONTROL_BUSY) ||
04911 (f->subclass == AST_CONTROL_CONGESTION) ) {
04912 ast_frfree(f);
04913 break;
04914 }
04915 }
04916 ast_frfree(f);
04917 }
04918 if (chan->_state == AST_STATE_UP) {
04919 if (!ast_strlen_zero(as->app)) {
04920 app = pbx_findapp(as->app);
04921 if (app) {
04922 if (option_verbose > 2)
04923 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04924 pbx_exec(chan, app, as->appdata, 1);
04925 } else
04926 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04927 } else {
04928 if (!ast_strlen_zero(as->context))
04929 ast_copy_string(chan->context, as->context, sizeof(chan->context));
04930 if (!ast_strlen_zero(as->exten))
04931 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
04932 if (as->priority > 0)
04933 chan->priority = as->priority;
04934
04935 if (ast_pbx_run(chan)) {
04936 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04937 } else {
04938
04939 chan = NULL;
04940 }
04941 }
04942
04943 }
04944 free(as);
04945 if (chan)
04946 ast_hangup(chan);
04947 return NULL;
04948 }
04949
04950
04951
04952
04953
04954
04955 int ast_pbx_outgoing_cdr_failed(void)
04956 {
04957
04958 struct ast_channel *chan = ast_channel_alloc(0);
04959 if(!chan) {
04960
04961 ast_log(LOG_WARNING, "Unable to allocate channel structure for CDR record\n");
04962 return -1;
04963 }
04964
04965 chan->cdr = ast_cdr_alloc();
04966
04967 if(!chan->cdr) {
04968
04969 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
04970 ast_channel_free(chan);
04971 return -1;
04972 }
04973
04974
04975 ast_cdr_init(chan->cdr, chan);
04976 ast_cdr_start(chan->cdr);
04977 ast_cdr_end(chan->cdr);
04978 ast_cdr_failed(chan->cdr);
04979 ast_cdr_detach(chan->cdr);
04980 ast_channel_free(chan);
04981
04982 return 0;
04983 }
04984
04985 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)
04986 {
04987 struct ast_channel *chan;
04988 struct async_stat *as;
04989 int res = -1, cdr_res = -1;
04990 struct outgoing_helper oh;
04991 pthread_attr_t attr;
04992
04993 if (sync) {
04994 LOAD_OH(oh);
04995 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
04996 if (channel) {
04997 *channel = chan;
04998 if (chan)
04999 ast_mutex_lock(&chan->lock);
05000 }
05001 if (chan) {
05002 if (chan->cdr) {
05003 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
05004 } else {
05005 chan->cdr = ast_cdr_alloc();
05006 if (!chan->cdr) {
05007
05008 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
05009 free(chan->pbx);
05010 res = -1;
05011 goto outgoing_exten_cleanup;
05012 }
05013
05014 ast_cdr_init(chan->cdr, chan);
05015 ast_cdr_start(chan->cdr);
05016 }
05017 if (chan->_state == AST_STATE_UP) {
05018 res = 0;
05019 if (option_verbose > 3)
05020 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05021
05022 if (sync > 1) {
05023 if (channel)
05024 ast_mutex_unlock(&chan->lock);
05025 if (ast_pbx_run(chan)) {
05026 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05027 if (channel)
05028 *channel = NULL;
05029 ast_hangup(chan);
05030 res = -1;
05031 }
05032 } else {
05033 if (ast_pbx_start(chan)) {
05034 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05035 if (channel) {
05036 *channel = NULL;
05037 ast_mutex_unlock(&chan->lock);
05038 }
05039 ast_hangup(chan);
05040 res = -1;
05041 }
05042 }
05043 } else {
05044 if (option_verbose > 3)
05045 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05046
05047 if(chan->cdr) {
05048
05049
05050 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05051 ast_cdr_failed(chan->cdr);
05052 }
05053
05054 if (channel) {
05055 *channel = NULL;
05056 ast_mutex_unlock(&chan->lock);
05057 }
05058 ast_hangup(chan);
05059 }
05060 }
05061
05062 if (res < 0) {
05063 if (*reason == 0) {
05064
05065 cdr_res = ast_pbx_outgoing_cdr_failed();
05066 if (cdr_res != 0) {
05067 res = cdr_res;
05068 goto outgoing_exten_cleanup;
05069 }
05070 }
05071
05072
05073
05074 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05075 chan = ast_channel_alloc(0);
05076 if (chan) {
05077 ast_copy_string(chan->name, "OutgoingSpoolFailed", sizeof(chan->name));
05078 if (!ast_strlen_zero(context))
05079 ast_copy_string(chan->context, context, sizeof(chan->context));
05080 ast_copy_string(chan->exten, "failed", sizeof(chan->exten));
05081 chan->priority = 1;
05082 ast_set_variables(chan, vars);
05083 if (account)
05084 ast_cdr_setaccount(chan, account);
05085 ast_pbx_run(chan);
05086 } else
05087 ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
05088 }
05089 }
05090 } else {
05091 as = malloc(sizeof(struct async_stat));
05092 if (!as) {
05093 res = -1;
05094 goto outgoing_exten_cleanup;
05095 }
05096 memset(as, 0, sizeof(struct async_stat));
05097 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05098 if (channel) {
05099 *channel = chan;
05100 if (chan)
05101 ast_mutex_lock(&chan->lock);
05102 }
05103 if (!chan) {
05104 free(as);
05105 res = -1;
05106 goto outgoing_exten_cleanup;
05107 }
05108 as->chan = chan;
05109 ast_copy_string(as->context, context, sizeof(as->context));
05110 ast_copy_string(as->exten, exten, sizeof(as->exten));
05111 as->priority = priority;
05112 as->timeout = timeout;
05113 ast_set_variables(chan, vars);
05114 if (account)
05115 ast_cdr_setaccount(chan, account);
05116 pthread_attr_init(&attr);
05117 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05118 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05119 ast_log(LOG_WARNING, "Failed to start async wait\n");
05120 free(as);
05121 if (channel) {
05122 *channel = NULL;
05123 ast_mutex_unlock(&chan->lock);
05124 }
05125 ast_hangup(chan);
05126 res = -1;
05127 goto outgoing_exten_cleanup;
05128 }
05129 res = 0;
05130 }
05131 outgoing_exten_cleanup:
05132 ast_variables_destroy(vars);
05133 return res;
05134 }
05135
05136 struct app_tmp {
05137 char app[256];
05138 char data[256];
05139 struct ast_channel *chan;
05140 pthread_t t;
05141 };
05142
05143 static void *ast_pbx_run_app(void *data)
05144 {
05145 struct app_tmp *tmp = data;
05146 struct ast_app *app;
05147 app = pbx_findapp(tmp->app);
05148 if (app) {
05149 if (option_verbose > 3)
05150 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05151 pbx_exec(tmp->chan, app, tmp->data, 1);
05152 } else
05153 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05154 ast_hangup(tmp->chan);
05155 free(tmp);
05156 return NULL;
05157 }
05158
05159 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)
05160 {
05161 struct ast_channel *chan;
05162 struct async_stat *as;
05163 struct app_tmp *tmp;
05164 int res = -1, cdr_res = -1;
05165 struct outgoing_helper oh;
05166 pthread_attr_t attr;
05167
05168 memset(&oh, 0, sizeof(oh));
05169 oh.vars = vars;
05170 oh.account = account;
05171
05172 if (locked_channel)
05173 *locked_channel = NULL;
05174 if (ast_strlen_zero(app)) {
05175 res = -1;
05176 goto outgoing_app_cleanup;
05177 }
05178 if (sync) {
05179 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05180 if (chan) {
05181 if (chan->cdr) {
05182 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
05183 } else {
05184 chan->cdr = ast_cdr_alloc();
05185 if(!chan->cdr) {
05186
05187 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
05188 free(chan->pbx);
05189 res = -1;
05190 goto outgoing_app_cleanup;
05191 }
05192
05193 ast_cdr_init(chan->cdr, chan);
05194 ast_cdr_start(chan->cdr);
05195 }
05196 ast_set_variables(chan, vars);
05197 if (account)
05198 ast_cdr_setaccount(chan, account);
05199 if (chan->_state == AST_STATE_UP) {
05200 res = 0;
05201 if (option_verbose > 3)
05202 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05203 tmp = malloc(sizeof(struct app_tmp));
05204 if (tmp) {
05205 memset(tmp, 0, sizeof(struct app_tmp));
05206 ast_copy_string(tmp->app, app, sizeof(tmp->app));
05207 if (appdata)
05208 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05209 tmp->chan = chan;
05210 if (sync > 1) {
05211 if (locked_channel)
05212 ast_mutex_unlock(&chan->lock);
05213 ast_pbx_run_app(tmp);
05214 } else {
05215 pthread_attr_init(&attr);
05216 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05217 if (locked_channel)
05218 ast_mutex_lock(&chan->lock);
05219 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05220 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05221 free(tmp);
05222 if (locked_channel)
05223 ast_mutex_unlock(&chan->lock);
05224 ast_hangup(chan);
05225 res = -1;
05226 } else {
05227 if (locked_channel)
05228 *locked_channel = chan;
05229 }
05230 }
05231 } else {
05232 ast_log(LOG_ERROR, "Out of memory :(\n");
05233 res = -1;
05234 }
05235 } else {
05236 if (option_verbose > 3)
05237 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05238 if (chan->cdr) {
05239
05240
05241 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05242 ast_cdr_failed(chan->cdr);
05243 }
05244 ast_hangup(chan);
05245 }
05246 }
05247
05248 if (res < 0) {
05249 if (*reason == 0) {
05250
05251 cdr_res = ast_pbx_outgoing_cdr_failed();
05252 if (cdr_res != 0) {
05253 res = cdr_res;
05254 goto outgoing_app_cleanup;
05255 }
05256 }
05257 }
05258
05259 } else {
05260 as = malloc(sizeof(struct async_stat));
05261 if (!as) {
05262 res = -1;
05263 goto outgoing_app_cleanup;
05264 }
05265 memset(as, 0, sizeof(struct async_stat));
05266 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05267 if (!chan) {
05268 free(as);
05269 res = -1;
05270 goto outgoing_app_cleanup;
05271 }
05272 as->chan = chan;
05273 ast_copy_string(as->app, app, sizeof(as->app));
05274 if (appdata)
05275 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
05276 as->timeout = timeout;
05277 ast_set_variables(chan, vars);
05278 if (account)
05279 ast_cdr_setaccount(chan, account);
05280
05281 pthread_attr_init(&attr);
05282 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05283 if (locked_channel)
05284 ast_mutex_lock(&chan->lock);
05285 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05286 ast_log(LOG_WARNING, "Failed to start async wait\n");
05287 free(as);
05288 if (locked_channel)
05289 ast_mutex_unlock(&chan->lock);
05290 ast_hangup(chan);
05291 res = -1;
05292 goto outgoing_app_cleanup;
05293 } else {
05294 if (locked_channel)
05295 *locked_channel = chan;
05296 }
05297 res = 0;
05298 }
05299 outgoing_app_cleanup:
05300 ast_variables_destroy(vars);
05301 return res;
05302 }
05303
05304 static void destroy_exten(struct ast_exten *e)
05305 {
05306 if (e->priority == PRIORITY_HINT)
05307 ast_remove_hint(e);
05308
05309 if (e->datad)
05310 e->datad(e->data);
05311 free(e);
05312 }
05313
05314 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05315 {
05316 struct ast_context *tmp, *tmpl=NULL;
05317 struct ast_include *tmpi, *tmpil= NULL;
05318 struct ast_sw *sw, *swl= NULL;
05319 struct ast_exten *e, *el, *en;
05320 struct ast_ignorepat *ipi, *ipl = NULL;
05321
05322 ast_mutex_lock(&conlock);
05323 tmp = contexts;
05324 while(tmp) {
05325 if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
05326 (!registrar || !strcasecmp(registrar, tmp->registrar))) {
05327
05328
05329 if (ast_mutex_lock(&tmp->lock)) {
05330 ast_log(LOG_WARNING, "Unable to lock context lock\n");
05331 return;
05332 }
05333 if (tmpl)
05334 tmpl->next = tmp->next;
05335 else
05336 contexts = tmp->next;
05337
05338
05339 ast_mutex_unlock(&tmp->lock);
05340 for (tmpi = tmp->includes; tmpi; ) {
05341
05342 tmpil = tmpi;
05343 tmpi = tmpi->next;
05344 free(tmpil);
05345 }
05346 for (ipi = tmp->ignorepats; ipi; ) {
05347
05348 ipl = ipi;
05349 ipi = ipi->next;
05350 free(ipl);
05351 }
05352 for (sw = tmp->alts; sw; ) {
05353
05354 swl = sw;
05355 sw = sw->next;
05356 free(swl);
05357 swl = sw;
05358 }
05359 for (e = tmp->root; e;) {
05360 for (en = e->peer; en;) {
05361 el = en;
05362 en = en->peer;
05363 destroy_exten(el);
05364 }
05365 el = e;
05366 e = e->next;
05367 destroy_exten(el);
05368 }
05369 ast_mutex_destroy(&tmp->lock);
05370 free(tmp);
05371 if (!con) {
05372
05373 tmp = contexts;
05374 tmpl = NULL;
05375 tmpil = NULL;
05376 continue;
05377 }
05378 ast_mutex_unlock(&conlock);
05379 return;
05380 }
05381 tmpl = tmp;
05382 tmp = tmp->next;
05383 }
05384 ast_mutex_unlock(&conlock);
05385 }
05386
05387 void ast_context_destroy(struct ast_context *con, const char *registrar)
05388 {
05389 __ast_context_destroy(con,registrar);
05390 }
05391
05392 static void wait_for_hangup(struct ast_channel *chan, void *data)
05393 {
05394 int res;
05395 struct ast_frame *f;
05396 int waittime;
05397
05398 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
05399 waittime = -1;
05400 if (waittime > -1) {
05401 ast_safe_sleep(chan, waittime * 1000);
05402 } else do {
05403 res = ast_waitfor(chan, -1);
05404 if (res < 0)
05405 return;
05406 f = ast_read(chan);
05407 if (f)
05408 ast_frfree(f);
05409 } while(f);
05410 }
05411
05412
05413
05414
05415 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05416 {
05417 ast_indicate(chan, AST_CONTROL_PROGRESS);
05418 return 0;
05419 }
05420
05421
05422
05423
05424 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05425 {
05426 ast_indicate(chan, AST_CONTROL_RINGING);
05427 return 0;
05428 }
05429
05430
05431
05432
05433 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05434 {
05435 ast_indicate(chan, AST_CONTROL_BUSY);
05436 if (chan->_state != AST_STATE_UP)
05437 ast_setstate(chan, AST_STATE_BUSY);
05438 wait_for_hangup(chan, data);
05439 return -1;
05440 }
05441
05442
05443
05444
05445 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
05446 {
05447 ast_indicate(chan, AST_CONTROL_CONGESTION);
05448 if (chan->_state != AST_STATE_UP)
05449 ast_setstate(chan, AST_STATE_BUSY);
05450 wait_for_hangup(chan, data);
05451 return -1;
05452 }
05453
05454
05455
05456
05457 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05458 {
05459 int delay = 0;
05460 int res;
05461
05462 if (chan->_state == AST_STATE_UP)
05463 delay = 0;
05464 else if (!ast_strlen_zero(data))
05465 delay = atoi(data);
05466
05467 res = ast_answer(chan);
05468 if (res)
05469 return res;
05470
05471 if (delay)
05472 res = ast_safe_sleep(chan, delay);
05473
05474 return res;
05475 }
05476
05477
05478
05479
05480 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
05481 {
05482 static int deprecation_warning = 0;
05483
05484 if (!deprecation_warning) {
05485 ast_log(LOG_WARNING, "SetLanguage is deprecated, please use Set(LANGUAGE()=language) instead.\n");
05486 deprecation_warning = 1;
05487 }
05488
05489
05490 if (!ast_strlen_zero(data))
05491 ast_copy_string(chan->language, data, sizeof(chan->language));
05492
05493 return 0;
05494 }
05495
05496 AST_APP_OPTIONS(resetcdr_opts, {
05497 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05498 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05499 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05500 });
05501
05502
05503
05504
05505 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05506 {
05507 char *args;
05508 struct ast_flags flags = { 0 };
05509
05510 if (!ast_strlen_zero(data)) {
05511 args = ast_strdupa(data);
05512 if (!args) {
05513 ast_log(LOG_ERROR, "Out of memory!\n");
05514 return -1;
05515 }
05516 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05517 }
05518
05519 ast_cdr_reset(chan->cdr, &flags);
05520
05521 return 0;
05522 }
05523
05524
05525
05526
05527 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
05528 {
05529
05530 if (data)
05531 ast_cdr_setaccount(chan, (char *)data);
05532 else
05533 ast_cdr_setaccount(chan, "");
05534 return 0;
05535 }
05536
05537
05538
05539
05540 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05541 {
05542
05543 if (data)
05544 ast_cdr_setamaflags(chan, (char *)data);
05545 else
05546 ast_cdr_setamaflags(chan, "");
05547 return 0;
05548 }
05549
05550
05551
05552
05553 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05554 {
05555
05556 if (!chan->hangupcause)
05557 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05558 return -1;
05559 }
05560
05561
05562
05563
05564 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05565 {
05566 int res=0;
05567 char *s, *ts;
05568 struct ast_timing timing;
05569
05570 if (ast_strlen_zero(data)) {
05571 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05572 return -1;
05573 }
05574
05575 if ((s = ast_strdupa((char *) data))) {
05576 ts = s;
05577
05578
05579 strsep(&ts,"?");
05580
05581
05582 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05583 res = pbx_builtin_goto(chan, (void *)ts);
05584 } else {
05585 ast_log(LOG_ERROR, "Memory Error!\n");
05586 }
05587 return res;
05588 }
05589
05590
05591
05592
05593 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05594 {
05595 int res = 0;
05596 char *ptr1, *ptr2;
05597 struct ast_timing timing;
05598 struct ast_app *app;
05599 const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05600
05601 if (ast_strlen_zero(data)) {
05602 ast_log(LOG_WARNING, "%s\n", usage);
05603 return -1;
05604 }
05605
05606 ptr1 = ast_strdupa(data);
05607
05608 if (!ptr1) {
05609 ast_log(LOG_ERROR, "Out of Memory!\n");
05610 return -1;
05611 }
05612
05613 ptr2 = ptr1;
05614
05615 strsep(&ptr2,"?");
05616 if(!ast_build_timing(&timing, ptr1)) {
05617 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", ptr1, usage);
05618 res = -1;
05619 }
05620
05621 if (!res && ast_check_timing(&timing)) {
05622 if (!ptr2) {
05623 ast_log(LOG_WARNING, "%s\n", usage);
05624 }
05625
05626
05627
05628 if((ptr1 = strchr(ptr2, '|'))) {
05629 *ptr1 = '\0';
05630 ptr1++;
05631 }
05632
05633 if ((app = pbx_findapp(ptr2))) {
05634 res = pbx_exec(chan, app, ptr1 ? ptr1 : "", 1);
05635 } else {
05636 ast_log(LOG_WARNING, "Cannot locate application %s\n", ptr2);
05637 res = -1;
05638 }
05639 }
05640
05641 return res;
05642 }
05643
05644
05645
05646
05647 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05648 {
05649 int ms;
05650
05651
05652 if (data && atof((char *)data)) {
05653 ms = atof((char *)data) * 1000;
05654 return ast_safe_sleep(chan, ms);
05655 }
05656 return 0;
05657 }
05658
05659
05660
05661
05662 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05663 {
05664 int ms, res, argc;
05665 char *args;
05666 char *argv[2];
05667 char *options = NULL;
05668 char *timeout = NULL;
05669 struct ast_flags flags = {0};
05670 char *opts[1] = { NULL };
05671
05672 args = ast_strdupa(data);
05673
05674 if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
05675 if (argc > 0) {
05676 timeout = argv[0];
05677 if (argc > 1)
05678 options = argv[1];
05679 }
05680 }
05681
05682 if (options)
05683 ast_app_parse_options(waitexten_opts, &flags, opts, options);
05684
05685 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05686 ast_moh_start(chan, opts[0]);
05687
05688
05689 if (timeout && atof((char *)timeout))
05690 ms = atof((char *)timeout) * 1000;
05691 else if (chan->pbx)
05692 ms = chan->pbx->rtimeout * 1000;
05693 else
05694 ms = 10000;
05695 res = ast_waitfordigit(chan, ms);
05696 if (!res) {
05697 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05698 if (option_verbose > 2)
05699 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05700 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05701 if (option_verbose > 2)
05702 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05703 ast_copy_string(chan->exten, "t", sizeof(chan->exten));
05704 chan->priority = 0;
05705 } else {
05706 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05707 res = -1;
05708 }
05709 }
05710
05711 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05712 ast_moh_stop(chan);
05713
05714 return res;
05715 }
05716
05717
05718
05719
05720 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05721 {
05722 int res = 0;
05723 int argc;
05724 char *parse;
05725 char *argv[4];
05726 char *options = NULL;
05727 char *filename = NULL;
05728 char *front = NULL, *back = NULL;
05729 char *lang = NULL;
05730 char *context = NULL;
05731 struct ast_flags flags = {0};
05732
05733 parse = ast_strdupa(data);
05734
05735 if ((argc = ast_app_separate_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
05736 switch (argc) {
05737 case 4:
05738 context = argv[3];
05739 case 3:
05740 lang = argv[2];
05741 case 2:
05742 options = argv[1];
05743 case 1:
05744 filename = argv[0];
05745 break;
05746 default:
05747 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05748 return -1;
05749 }
05750 }
05751
05752 if (!lang)
05753 lang = chan->language;
05754
05755 if (!context)
05756 context = chan->context;
05757
05758 if (options) {
05759 if (!strcasecmp(options, "skip"))
05760 flags.flags = BACKGROUND_SKIP;
05761 else if (!strcasecmp(options, "noanswer"))
05762 flags.flags = BACKGROUND_NOANSWER;
05763 else
05764 ast_app_parse_options(background_opts, &flags, NULL, options);
05765 }
05766
05767
05768 if (chan->_state != AST_STATE_UP) {
05769 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05770 return 0;
05771 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05772 res = ast_answer(chan);
05773 }
05774 }
05775
05776 if (!res) {
05777
05778 ast_stopstream(chan);
05779
05780 front = filename;
05781 while(!res && front) {
05782 if((back = strchr(front, '&'))) {
05783 *back = '\0';
05784 back++;
05785 }
05786 res = ast_streamfile(chan, front, lang);
05787 if (!res) {
05788 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05789 res = ast_waitstream(chan, "");
05790 } else {
05791 if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05792 res = ast_waitstream_exten(chan, context);
05793 } else {
05794 res = ast_waitstream(chan, AST_DIGIT_ANY);
05795 }
05796 }
05797 ast_stopstream(chan);
05798 } else {
05799 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05800 res = 0;
05801 break;
05802 }
05803 front = back;
05804 }
05805 }
05806 if (context != chan->context && res) {
05807 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05808 ast_copy_string(chan->context, context, sizeof(chan->context));
05809 chan->priority = 0;
05810 return 0;
05811 } else {
05812 return res;
05813 }
05814 }
05815
05816
05817
05818
05819
05820 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
05821 {
05822 static int deprecation_warning = 0;
05823 int x = atoi((char *) data);
05824
05825 if (!deprecation_warning) {
05826 ast_log(LOG_WARNING, "AbsoluteTimeout is deprecated, please use Set(TIMEOUT(absolute)=timeout) instead.\n");
05827 deprecation_warning = 1;
05828 }
05829
05830
05831 ast_channel_setwhentohangup(chan,x);
05832 if (option_verbose > 2)
05833 ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
05834 return 0;
05835 }
05836
05837
05838
05839
05840
05841 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
05842 {
05843 static int deprecation_warning = 0;
05844
05845 if (!deprecation_warning) {
05846 ast_log(LOG_WARNING, "ResponseTimeout is deprecated, please use Set(TIMEOUT(response)=timeout) instead.\n");
05847 deprecation_warning = 1;
05848 }
05849
05850
05851 if (!chan->pbx)
05852 return 0;
05853
05854
05855 chan->pbx->rtimeout = atoi((char *)data);
05856 if (option_verbose > 2)
05857 ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
05858 return 0;
05859 }
05860
05861
05862
05863
05864
05865 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
05866 {
05867 static int deprecation_warning = 0;
05868
05869 if (!deprecation_warning) {
05870 ast_log(LOG_WARNING, "DigitTimeout is deprecated, please use Set(TIMEOUT(digit)=timeout) instead.\n");
05871 deprecation_warning = 1;
05872 }
05873
05874
05875 if (!chan->pbx)
05876 return 0;
05877
05878
05879 chan->pbx->dtimeout = atoi((char *)data);
05880 if (option_verbose > 2)
05881 ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
05882 return 0;
05883 }
05884
05885
05886
05887
05888 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05889 {
05890 int res;
05891 res = ast_parseable_goto(chan, (const char *) data);
05892 if (!res && (option_verbose > 2))
05893 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05894 return res;
05895 }
05896
05897
05898 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05899 {
05900 struct ast_var_t *variables;
05901 char *var, *val;
05902 int total = 0;
05903
05904 if (!chan)
05905 return 0;
05906
05907 memset(buf, 0, size);
05908
05909 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05910 if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))) {
05911 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05912 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05913 break;
05914 } else
05915 total++;
05916 } else
05917 break;
05918 }
05919
05920 return total;
05921 }
05922
05923 char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05924 {
05925 struct ast_var_t *variables;
05926 char *ret = NULL;
05927 int i;
05928 struct varshead *places[2] = { NULL, &globals };
05929
05930 if (!name)
05931 return NULL;
05932 if (chan)
05933 places[0] = &chan->varshead;
05934
05935 for (i = 0; i < 2; i++) {
05936 if (!places[i])
05937 continue;
05938 if (places[i] == &globals)
05939 ast_mutex_lock(&globalslock);
05940 AST_LIST_TRAVERSE(places[i], variables, entries) {
05941 if (!strcmp(name, ast_var_name(variables))) {
05942 ret = ast_var_value(variables);
05943 break;
05944 }
05945 }
05946 if (places[i] == &globals)
05947 ast_mutex_unlock(&globalslock);
05948 if (ret)
05949 break;
05950 }
05951
05952 return ret;
05953 }
05954
05955 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05956 {
05957 struct ast_var_t *newvariable;
05958 struct varshead *headp;
05959
05960 if (name[strlen(name)-1] == ')') {
05961 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05962 return ast_func_write(chan, name, value);
05963 }
05964
05965 headp = (chan) ? &chan->varshead : &globals;
05966
05967 if (value) {
05968 if ((option_verbose > 1) && (headp == &globals))
05969 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05970 newvariable = ast_var_assign(name, value);
05971 if (headp == &globals)
05972 ast_mutex_lock(&globalslock);
05973 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05974 if (headp == &globals)
05975 ast_mutex_unlock(&globalslock);
05976 }
05977 }
05978
05979 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
05980 {
05981 struct ast_var_t *newvariable;
05982 struct varshead *headp;
05983 const char *nametail = name;
05984
05985 if (name[strlen(name)-1] == ')')
05986 return ast_func_write(chan, name, value);
05987
05988 headp = (chan) ? &chan->varshead : &globals;
05989
05990
05991 if (*nametail == '_') {
05992 nametail++;
05993 if (*nametail == '_')
05994 nametail++;
05995 }
05996
05997 if (headp == &globals)
05998 ast_mutex_lock(&globalslock);
05999 AST_LIST_TRAVERSE (headp, newvariable, entries) {
06000 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
06001
06002 AST_LIST_REMOVE(headp, newvariable, entries);
06003 ast_var_delete(newvariable);
06004 break;
06005 }
06006 }
06007
06008 if (value) {
06009 if ((option_verbose > 1) && (headp == &globals))
06010 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
06011 newvariable = ast_var_assign(name, value);
06012 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
06013 }
06014
06015 if (headp == &globals)
06016 ast_mutex_unlock(&globalslock);
06017 }
06018
06019 int pbx_builtin_setvar_old(struct ast_channel *chan, void *data)
06020 {
06021 static int deprecation_warning = 0;
06022
06023 if (!deprecation_warning) {
06024 ast_log(LOG_WARNING, "SetVar is deprecated, please use Set instead.\n");
06025 deprecation_warning = 1;
06026 }
06027
06028 return pbx_builtin_setvar(chan, data);
06029 }
06030
06031 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
06032 {
06033 char *name, *value, *mydata;
06034 int argc;
06035 char *argv[24];
06036 int global = 0;
06037 int x;
06038
06039 if (ast_strlen_zero(data)) {
06040 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
06041 return 0;
06042 }
06043
06044 mydata = ast_strdupa(data);
06045 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
06046
06047
06048 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
06049 argc--;
06050 if (strchr(argv[argc], 'g'))
06051 global = 1;
06052 }
06053
06054 for (x = 0; x < argc; x++) {
06055 name = argv[x];
06056 if ((value = strchr(name, '='))) {
06057 *value = '\0';
06058 value++;
06059 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
06060 } else
06061 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
06062 }
06063
06064 return(0);
06065 }
06066
06067 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
06068 {
06069 char *name;
06070 char *value;
06071 char *stringp=NULL;
06072 char *channel;
06073 struct ast_channel *chan2;
06074 char tmp[VAR_BUF_SIZE]="";
06075 char *s;
06076
06077 if (ast_strlen_zero(data)) {
06078 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06079 return 0;
06080 }
06081
06082 stringp = ast_strdupa(data);
06083 name = strsep(&stringp,"=");
06084 channel = strsep(&stringp,"|");
06085 value = strsep(&stringp,"\0");
06086 if (channel && value && name) {
06087 chan2 = ast_get_channel_by_name_locked(channel);
06088 if (chan2) {
06089 s = alloca(strlen(value) + 4);
06090 if (s) {
06091 sprintf(s, "${%s}", value);
06092 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
06093 }
06094 ast_mutex_unlock(&chan2->lock);
06095 }
06096 pbx_builtin_setvar_helper(chan, name, tmp);
06097 }
06098
06099 return(0);
06100 }
06101
06102 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
06103 {
06104 char *name;
06105 char *value;
06106 char *stringp = NULL;
06107
06108 if (ast_strlen_zero(data)) {
06109 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06110 return 0;
06111 }
06112
06113 stringp = data;
06114 name = strsep(&stringp, "=");
06115 value = strsep(&stringp, "\0");
06116
06117 pbx_builtin_setvar_helper(NULL, name, value);
06118
06119 return(0);
06120 }
06121
06122 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
06123 {
06124 return 0;
06125 }
06126
06127
06128 void pbx_builtin_clear_globals(void)
06129 {
06130 struct ast_var_t *vardata;
06131
06132 ast_mutex_lock(&globalslock);
06133 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
06134 ast_var_delete(vardata);
06135 ast_mutex_unlock(&globalslock);
06136 }
06137
06138 int pbx_checkcondition(char *condition)
06139 {
06140 if (condition) {
06141 if (*condition == '\0') {
06142
06143 return 0;
06144 } else if (*condition >= '0' && *condition <= '9') {
06145
06146 return atoi(condition);
06147 } else {
06148
06149 return 1;
06150 }
06151 } else {
06152
06153 return 0;
06154 }
06155 }
06156
06157 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
06158 {
06159 char *condition, *branch1, *branch2, *branch;
06160 char *s;
06161 int rc;
06162 char *stringp=NULL;
06163
06164 if (ast_strlen_zero(data)) {
06165 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
06166 return 0;
06167 }
06168
06169 s = ast_strdupa(data);
06170 stringp = s;
06171 condition = strsep(&stringp,"?");
06172 branch1 = strsep(&stringp,":");
06173 branch2 = strsep(&stringp,"");
06174 branch = pbx_checkcondition(condition) ? branch1 : branch2;
06175
06176 if (ast_strlen_zero(branch)) {
06177 ast_log(LOG_DEBUG, "Not taking any branch\n");
06178 return 0;
06179 }
06180
06181 rc = pbx_builtin_goto(chan, branch);
06182
06183 return rc;
06184 }
06185
06186 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
06187 {
06188 int res = 0;
06189 char tmp[256];
06190 char *number = (char *) NULL;
06191 char *options = (char *) NULL;
06192
06193
06194 if (ast_strlen_zero(data)) {
06195 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06196 return -1;
06197 }
06198 ast_copy_string(tmp, (char *) data, sizeof(tmp));
06199 number=tmp;
06200 strsep(&number, "|");
06201 options = strsep(&number, "|");
06202 if (options) {
06203 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06204 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06205 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06206 return -1;
06207 }
06208 }
06209 return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
06210 }
06211
06212 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06213 {
06214 int res = 0;
06215
06216 if (data)
06217 res = ast_say_digit_str(chan, (char *)data, "", chan->language);
06218 return res;
06219 }
06220
06221 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06222 {
06223 int res = 0;
06224
06225 if (data)
06226 res = ast_say_character_str(chan, (char *)data, "", chan->language);
06227 return res;
06228 }
06229
06230 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06231 {
06232 int res = 0;
06233
06234 if (data)
06235 res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
06236 return res;
06237 }
06238
06239 int load_pbx(void)
06240 {
06241 int x;
06242
06243
06244 if (option_verbose) {
06245 ast_verbose( "Asterisk PBX Core Initializing\n");
06246 ast_verbose( "Registering builtin applications:\n");
06247 }
06248 AST_LIST_HEAD_INIT_NOLOCK(&globals);
06249 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
06250
06251
06252 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06253 if (option_verbose)
06254 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06255 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06256 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06257 return -1;
06258 }
06259 }
06260 return 0;
06261 }
06262
06263
06264
06265
06266 int ast_lock_contexts()
06267 {
06268 return ast_mutex_lock(&conlock);
06269 }
06270
06271 int ast_unlock_contexts()
06272 {
06273 return ast_mutex_unlock(&conlock);
06274 }
06275
06276
06277
06278
06279 int ast_lock_context(struct ast_context *con)
06280 {
06281 return ast_mutex_lock(&con->lock);
06282 }
06283
06284 int ast_unlock_context(struct ast_context *con)
06285 {
06286 return ast_mutex_unlock(&con->lock);
06287 }
06288
06289
06290
06291
06292 const char *ast_get_context_name(struct ast_context *con)
06293 {
06294 return con ? con->name : NULL;
06295 }
06296
06297 const char *ast_get_extension_name(struct ast_exten *exten)
06298 {
06299 return exten ? exten->exten : NULL;
06300 }
06301
06302 const char *ast_get_extension_label(struct ast_exten *exten)
06303 {
06304 return exten ? exten->label : NULL;
06305 }
06306
06307 const char *ast_get_include_name(struct ast_include *inc)
06308 {
06309 return inc ? inc->name : NULL;
06310 }
06311
06312 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06313 {
06314 return ip ? ip->pattern : NULL;
06315 }
06316
06317 int ast_get_extension_priority(struct ast_exten *exten)
06318 {
06319 return exten ? exten->priority : -1;
06320 }
06321
06322
06323
06324
06325 const char *ast_get_context_registrar(struct ast_context *c)
06326 {
06327 return c ? c->registrar : NULL;
06328 }
06329
06330 const char *ast_get_extension_registrar(struct ast_exten *e)
06331 {
06332 return e ? e->registrar : NULL;
06333 }
06334
06335 const char *ast_get_include_registrar(struct ast_include *i)
06336 {
06337 return i ? i->registrar : NULL;
06338 }
06339
06340 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06341 {
06342 return ip ? ip->registrar : NULL;
06343 }
06344
06345 int ast_get_extension_matchcid(struct ast_exten *e)
06346 {
06347 return e ? e->matchcid : 0;
06348 }
06349
06350 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06351 {
06352 return e ? e->cidmatch : NULL;
06353 }
06354
06355 const char *ast_get_extension_app(struct ast_exten *e)
06356 {
06357 return e ? e->app : NULL;
06358 }
06359
06360 void *ast_get_extension_app_data(struct ast_exten *e)
06361 {
06362 return e ? e->data : NULL;
06363 }
06364
06365 const char *ast_get_switch_name(struct ast_sw *sw)
06366 {
06367 return sw ? sw->name : NULL;
06368 }
06369
06370 const char *ast_get_switch_data(struct ast_sw *sw)
06371 {
06372 return sw ? sw->data : NULL;
06373 }
06374
06375 const char *ast_get_switch_registrar(struct ast_sw *sw)
06376 {
06377 return sw ? sw->registrar : NULL;
06378 }
06379
06380
06381
06382
06383 struct ast_context *ast_walk_contexts(struct ast_context *con)
06384 {
06385 if (!con)
06386 return contexts;
06387 else
06388 return con->next;
06389 }
06390
06391 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06392 struct ast_exten *exten)
06393 {
06394 if (!exten)
06395 return con ? con->root : NULL;
06396 else
06397 return exten->next;
06398 }
06399
06400 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06401 struct ast_sw *sw)
06402 {
06403 if (!sw)
06404 return con ? con->alts : NULL;
06405 else
06406 return sw->next;
06407 }
06408
06409 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06410 struct ast_exten *priority)
06411 {
06412 if (!priority)
06413 return exten;
06414 else
06415 return priority->peer;
06416 }
06417
06418 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06419 struct ast_include *inc)
06420 {
06421 if (!inc)
06422 return con ? con->includes : NULL;
06423 else
06424 return inc->next;
06425 }
06426
06427 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06428 struct ast_ignorepat *ip)
06429 {
06430 if (!ip)
06431 return con ? con->ignorepats : NULL;
06432 else
06433 return ip->next;
06434 }
06435
06436 int ast_context_verify_includes(struct ast_context *con)
06437 {
06438 struct ast_include *inc;
06439 int res = 0;
06440
06441 for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
06442 if (!ast_context_find(inc->rname)) {
06443 res = -1;
06444 ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
06445 ast_get_context_name(con), inc->rname);
06446 }
06447 return res;
06448 }
06449
06450
06451 static int __ast_goto_if_exists(struct ast_channel *chan, char *context, char *exten, int priority, int async)
06452 {
06453 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06454
06455 if (!chan)
06456 return -2;
06457
06458 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06459 if (ast_exists_extension(chan, context ? context : chan->context,
06460 exten ? exten : chan->exten, priority,
06461 chan->cid.cid_num))
06462 return goto_func(chan, context ? context : chan->context,
06463 exten ? exten : chan->exten, priority);
06464 else
06465 return -3;
06466 }
06467
06468 int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
06469 return __ast_goto_if_exists(chan, context, exten, priority, 0);
06470 }
06471
06472 int ast_async_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
06473 return __ast_goto_if_exists(chan, context, exten, priority, 1);
06474 }
06475
06476 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06477 {
06478 char *s;
06479 char *exten, *pri, *context;
06480 char *stringp=NULL;
06481 int ipri;
06482 int mode = 0;
06483
06484 if (ast_strlen_zero(goto_string)) {
06485 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06486 return -1;
06487 }
06488 s = ast_strdupa(goto_string);
06489 stringp=s;
06490 context = strsep(&stringp, "|");
06491 exten = strsep(&stringp, "|");
06492 if (!exten) {
06493
06494 pri = context;
06495 exten = NULL;
06496 context = NULL;
06497 } else {
06498 pri = strsep(&stringp, "|");
06499 if (!pri) {
06500
06501 pri = exten;
06502 exten = context;
06503 context = NULL;
06504 }
06505 }
06506 if (*pri == '+') {
06507 mode = 1;
06508 pri++;
06509 } else if (*pri == '-') {
06510 mode = -1;
06511 pri++;
06512 }
06513 if (sscanf(pri, "%d", &ipri) != 1) {
06514 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten,
06515 pri, chan->cid.cid_num)) < 1) {
06516 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06517 return -1;
06518 } else
06519 mode = 0;
06520 }
06521
06522
06523 if (exten && !strcasecmp(exten, "BYEXTENSION"))
06524 exten = NULL;
06525
06526 if (mode)
06527 ipri = chan->priority + (ipri * mode);
06528
06529 ast_explicit_goto(chan, context, exten, ipri);
06530 ast_cdr_update(chan);
06531 return 0;
06532
06533 }