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