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