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