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