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)
02527 ast_softhangup(c, c->hangupcause ? c->hangupcause : AST_CAUSE_NORMAL_CLEARING);
02528 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
02529 if (c->cdr && ast_opt_end_cdr_before_h_exten)
02530 ast_cdr_end(c->cdr);
02531 set_ext_pri(c, "h", 1);
02532 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02533 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02534
02535 if (option_debug)
02536 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02537 if (option_verbose > 1)
02538 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02539 break;
02540 }
02541 c->priority++;
02542 }
02543 }
02544 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02545
02546 pbx_destroy(c->pbx);
02547 c->pbx = NULL;
02548 if (res != AST_PBX_KEEPALIVE)
02549 ast_hangup(c);
02550 return 0;
02551 }
02552
02553
02554 static int increase_call_count(const struct ast_channel *c)
02555 {
02556 int failed = 0;
02557 double curloadavg;
02558 ast_mutex_lock(&maxcalllock);
02559 if (option_maxcalls) {
02560 if (countcalls >= option_maxcalls) {
02561 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
02562 failed = -1;
02563 }
02564 }
02565 if (option_maxload) {
02566 getloadavg(&curloadavg, 1);
02567 if (curloadavg >= option_maxload) {
02568 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
02569 failed = -1;
02570 }
02571 }
02572 if (!failed)
02573 countcalls++;
02574 ast_mutex_unlock(&maxcalllock);
02575
02576 return failed;
02577 }
02578
02579 static void decrease_call_count(void)
02580 {
02581 ast_mutex_lock(&maxcalllock);
02582 if (countcalls > 0)
02583 countcalls--;
02584 ast_mutex_unlock(&maxcalllock);
02585 }
02586
02587 static void destroy_exten(struct ast_exten *e)
02588 {
02589 if (e->priority == PRIORITY_HINT)
02590 ast_remove_hint(e);
02591
02592 if (e->datad)
02593 e->datad(e->data);
02594 free(e);
02595 }
02596
02597 static void *pbx_thread(void *data)
02598 {
02599
02600
02601
02602
02603
02604
02605
02606
02607 struct ast_channel *c = data;
02608
02609 __ast_pbx_run(c);
02610 decrease_call_count();
02611
02612 pthread_exit(NULL);
02613
02614 return NULL;
02615 }
02616
02617 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
02618 {
02619 pthread_t t;
02620 pthread_attr_t attr;
02621
02622 if (!c) {
02623 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
02624 return AST_PBX_FAILED;
02625 }
02626
02627 if (increase_call_count(c))
02628 return AST_PBX_CALL_LIMIT;
02629
02630
02631 pthread_attr_init(&attr);
02632 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02633 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
02634 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
02635 pthread_attr_destroy(&attr);
02636 return AST_PBX_FAILED;
02637 }
02638 pthread_attr_destroy(&attr);
02639
02640 return AST_PBX_SUCCESS;
02641 }
02642
02643 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
02644 {
02645 enum ast_pbx_result res = AST_PBX_SUCCESS;
02646
02647 if (increase_call_count(c))
02648 return AST_PBX_CALL_LIMIT;
02649
02650 res = __ast_pbx_run(c);
02651 decrease_call_count();
02652
02653 return res;
02654 }
02655
02656 int ast_active_calls(void)
02657 {
02658 return countcalls;
02659 }
02660
02661 int pbx_set_autofallthrough(int newval)
02662 {
02663 int oldval = autofallthrough;
02664 autofallthrough = newval;
02665 return oldval;
02666 }
02667
02668
02669
02670
02671 static struct ast_context *find_context_locked(const char *context)
02672 {
02673 struct ast_context *c = NULL;
02674
02675 ast_lock_contexts();
02676 while ( (c = ast_walk_contexts(c)) ) {
02677 if (!strcmp(ast_get_context_name(c), context))
02678 return c;
02679 }
02680 ast_unlock_contexts();
02681
02682 return NULL;
02683 }
02684
02685
02686
02687
02688
02689
02690 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
02691 {
02692 int ret = -1;
02693 struct ast_context *c = find_context_locked(context);
02694
02695 if (c) {
02696
02697 ret = ast_context_remove_include2(c, include, registrar);
02698 ast_unlock_contexts();
02699 }
02700 return ret;
02701 }
02702
02703
02704
02705
02706
02707
02708
02709
02710
02711 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
02712 {
02713 struct ast_include *i, *pi = NULL;
02714 int ret = -1;
02715
02716 ast_mutex_lock(&con->lock);
02717
02718
02719 for (i = con->includes; i; pi = i, i = i->next) {
02720 if (!strcmp(i->name, include) &&
02721 (!registrar || !strcmp(i->registrar, registrar))) {
02722
02723 if (pi)
02724 pi->next = i->next;
02725 else
02726 con->includes = i->next;
02727
02728 free(i);
02729 ret = 0;
02730 break;
02731 }
02732 }
02733
02734 ast_mutex_unlock(&con->lock);
02735 return ret;
02736 }
02737
02738
02739
02740
02741
02742
02743 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
02744 {
02745 int ret = -1;
02746 struct ast_context *c = find_context_locked(context);
02747
02748 if (c) {
02749
02750 ret = ast_context_remove_switch2(c, sw, data, registrar);
02751 ast_unlock_contexts();
02752 }
02753 return ret;
02754 }
02755
02756
02757
02758
02759
02760
02761
02762
02763
02764 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
02765 {
02766 struct ast_sw *i;
02767 int ret = -1;
02768
02769 ast_mutex_lock(&con->lock);
02770
02771
02772 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
02773 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
02774 (!registrar || !strcmp(i->registrar, registrar))) {
02775
02776 AST_LIST_REMOVE_CURRENT(&con->alts, list);
02777 free(i);
02778 ret = 0;
02779 break;
02780 }
02781 }
02782 AST_LIST_TRAVERSE_SAFE_END
02783
02784 ast_mutex_unlock(&con->lock);
02785
02786 return ret;
02787 }
02788
02789
02790
02791
02792
02793
02794 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
02795 {
02796 int ret = -1;
02797 struct ast_context *c = find_context_locked(context);
02798
02799 if (c) {
02800 ret = ast_context_remove_extension2(c, extension, priority, registrar);
02801 ast_unlock_contexts();
02802 }
02803 return ret;
02804 }
02805
02806
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
02817 {
02818 struct ast_exten *exten, *prev_exten = NULL;
02819 struct ast_exten *peer;
02820
02821 ast_mutex_lock(&con->lock);
02822
02823
02824 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
02825 if (!strcmp(exten->exten, extension) &&
02826 (!registrar || !strcmp(exten->registrar, registrar)))
02827 break;
02828 }
02829 if (!exten) {
02830
02831 ast_mutex_unlock(&con->lock);
02832 return -1;
02833 }
02834
02835
02836 if (priority == 0) {
02837
02838 if (prev_exten)
02839 prev_exten->next = exten->next;
02840 else
02841 con->root = exten->next;
02842
02843
02844 while ( (peer = exten) ) {
02845 exten = peer->peer;
02846 destroy_exten(peer);
02847 }
02848 } else {
02849
02850 struct ast_exten *previous_peer = NULL;
02851
02852 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
02853 if (peer->priority == priority &&
02854 (!registrar || !strcmp(peer->registrar, registrar) ))
02855 break;
02856 }
02857 if (!peer) {
02858 ast_mutex_unlock(&con->lock);
02859 return -1;
02860 }
02861
02862 if (!previous_peer) {
02863
02864
02865
02866
02867 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
02868
02869 if (!prev_exten)
02870 con->root = next_node;
02871 else
02872 prev_exten->next = next_node;
02873 if (peer->peer)
02874 peer->peer->next = peer->next;
02875 } else {
02876 previous_peer->peer = peer->peer;
02877 }
02878
02879
02880 destroy_exten(peer);
02881
02882 }
02883 ast_mutex_unlock(&con->lock);
02884 return 0;
02885 }
02886
02887
02888
02889
02890
02891
02892
02893 int ast_context_lockmacro(const char *context)
02894 {
02895 struct ast_context *c = NULL;
02896 int ret = -1;
02897
02898 ast_lock_contexts();
02899
02900 while ((c = ast_walk_contexts(c))) {
02901 if (!strcmp(ast_get_context_name(c), context)) {
02902 ret = 0;
02903 break;
02904 }
02905 }
02906
02907 ast_unlock_contexts();
02908
02909
02910 if (ret == 0)
02911 ret = ast_mutex_lock(&c->macrolock);
02912
02913 return ret;
02914 }
02915
02916
02917
02918
02919
02920
02921 int ast_context_unlockmacro(const char *context)
02922 {
02923 struct ast_context *c = NULL;
02924 int ret = -1;
02925
02926 ast_lock_contexts();
02927
02928 while ((c = ast_walk_contexts(c))) {
02929 if (!strcmp(ast_get_context_name(c), context)) {
02930 ret = 0;
02931 break;
02932 }
02933 }
02934
02935 ast_unlock_contexts();
02936
02937
02938 if (ret == 0)
02939 ret = ast_mutex_unlock(&c->macrolock);
02940
02941 return ret;
02942 }
02943
02944
02945 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
02946 {
02947 struct ast_app *tmp, *cur = NULL;
02948 char tmps[80];
02949 int length;
02950
02951 AST_LIST_LOCK(&apps);
02952 AST_LIST_TRAVERSE(&apps, tmp, list) {
02953 if (!strcasecmp(app, tmp->name)) {
02954 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02955 AST_LIST_UNLOCK(&apps);
02956 return -1;
02957 }
02958 }
02959
02960 length = sizeof(*tmp) + strlen(app) + 1;
02961
02962 if (!(tmp = ast_calloc(1, length))) {
02963 AST_LIST_UNLOCK(&apps);
02964 return -1;
02965 }
02966
02967 strcpy(tmp->name, app);
02968 tmp->execute = execute;
02969 tmp->synopsis = synopsis;
02970 tmp->description = description;
02971
02972
02973 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
02974 if (strcasecmp(tmp->name, cur->name) < 0) {
02975 AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
02976 break;
02977 }
02978 }
02979 AST_LIST_TRAVERSE_SAFE_END
02980 if (!cur)
02981 AST_LIST_INSERT_TAIL(&apps, tmp, list);
02982
02983 if (option_verbose > 1)
02984 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02985
02986 AST_LIST_UNLOCK(&apps);
02987
02988 return 0;
02989 }
02990
02991
02992
02993
02994
02995 int ast_register_switch(struct ast_switch *sw)
02996 {
02997 struct ast_switch *tmp;
02998
02999 AST_LIST_LOCK(&switches);
03000 AST_LIST_TRAVERSE(&switches, tmp, list) {
03001 if (!strcasecmp(tmp->name, sw->name)) {
03002 AST_LIST_UNLOCK(&switches);
03003 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
03004 return -1;
03005 }
03006 }
03007 AST_LIST_INSERT_TAIL(&switches, sw, list);
03008 AST_LIST_UNLOCK(&switches);
03009
03010 return 0;
03011 }
03012
03013 void ast_unregister_switch(struct ast_switch *sw)
03014 {
03015 AST_LIST_LOCK(&switches);
03016 AST_LIST_REMOVE(&switches, sw, list);
03017 AST_LIST_UNLOCK(&switches);
03018 }
03019
03020
03021
03022
03023 static char show_applications_help[] =
03024 "Usage: core show applications [{like|describing} <text>]\n"
03025 " List applications which are currently available.\n"
03026 " If 'like', <text> will be a substring of the app name\n"
03027 " If 'describing', <text> will be a substring of the description\n";
03028
03029 static char show_functions_help[] =
03030 "Usage: core show functions [like <text>]\n"
03031 " List builtin functions, optionally only those matching a given string\n";
03032
03033 static char show_switches_help[] =
03034 "Usage: core show switches\n"
03035 " List registered switches\n";
03036
03037 static char show_hints_help[] =
03038 "Usage: core show hints\n"
03039 " List registered hints\n";
03040
03041 static char show_globals_help[] =
03042 "Usage: core show globals\n"
03043 " List current global dialplan variables and their values\n";
03044
03045 static char show_application_help[] =
03046 "Usage: core show application <application> [<application> [<application> [...]]]\n"
03047 " Describes a particular application.\n";
03048
03049 static char show_function_help[] =
03050 "Usage: core show function <function>\n"
03051 " Describe a particular dialplan function.\n";
03052
03053 static char show_dialplan_help[] =
03054 "Usage: core show dialplan [exten@][context]\n"
03055 " Show dialplan\n";
03056
03057 static char set_global_help[] =
03058 "Usage: core set global <name> <value>\n"
03059 " Set global dialplan variable <name> to <value>\n";
03060
03061
03062
03063
03064
03065
03066
03067
03068
03069
03070
03071 static char *complete_show_application(const char *line, const char *word, int pos, int state)
03072 {
03073 struct ast_app *a;
03074 char *ret = NULL;
03075 int which = 0;
03076 int wordlen = strlen(word);
03077
03078
03079 AST_LIST_LOCK(&apps);
03080 AST_LIST_TRAVERSE(&apps, a, list) {
03081 if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
03082 ret = strdup(a->name);
03083 break;
03084 }
03085 }
03086 AST_LIST_UNLOCK(&apps);
03087
03088 return ret;
03089 }
03090
03091 static int handle_show_application_deprecated(int fd, int argc, char *argv[])
03092 {
03093 struct ast_app *a;
03094 int app, no_registered_app = 1;
03095
03096 if (argc < 3)
03097 return RESULT_SHOWUSAGE;
03098
03099
03100 AST_LIST_LOCK(&apps);
03101 AST_LIST_TRAVERSE(&apps, a, list) {
03102
03103
03104 for (app = 2; app < argc; app++) {
03105 if (!strcasecmp(a->name, argv[app])) {
03106
03107 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03108 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03109 int synopsis_size, description_size;
03110
03111 no_registered_app = 0;
03112
03113 if (a->synopsis)
03114 synopsis_size = strlen(a->synopsis) + 23;
03115 else
03116 synopsis_size = strlen("Not available") + 23;
03117 synopsis = alloca(synopsis_size);
03118
03119 if (a->description)
03120 description_size = strlen(a->description) + 23;
03121 else
03122 description_size = strlen("Not available") + 23;
03123 description = alloca(description_size);
03124
03125 if (synopsis && description) {
03126 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
03127 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03128 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03129 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03130 term_color(synopsis,
03131 a->synopsis ? a->synopsis : "Not available",
03132 COLOR_CYAN, 0, synopsis_size);
03133 term_color(description,
03134 a->description ? a->description : "Not available",
03135 COLOR_CYAN, 0, description_size);
03136
03137 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03138 } else {
03139
03140 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
03141 "[Synopsis]\n %s\n\n"
03142 "[Description]\n%s\n",
03143 a->name,
03144 a->synopsis ? a->synopsis : "Not available",
03145 a->description ? a->description : "Not available");
03146 }
03147 }
03148 }
03149 }
03150 AST_LIST_UNLOCK(&apps);
03151
03152
03153 if (no_registered_app) {
03154 ast_cli(fd, "Your application(s) is (are) not registered\n");
03155 return RESULT_FAILURE;
03156 }
03157
03158 return RESULT_SUCCESS;
03159 }
03160
03161 static int handle_show_application(int fd, int argc, char *argv[])
03162 {
03163 struct ast_app *a;
03164 int app, no_registered_app = 1;
03165
03166 if (argc < 4)
03167 return RESULT_SHOWUSAGE;
03168
03169
03170 AST_LIST_LOCK(&apps);
03171 AST_LIST_TRAVERSE(&apps, a, list) {
03172
03173
03174 for (app = 3; app < argc; app++) {
03175 if (!strcasecmp(a->name, argv[app])) {
03176
03177 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03178 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03179 int synopsis_size, description_size;
03180
03181 no_registered_app = 0;
03182
03183 if (a->synopsis)
03184 synopsis_size = strlen(a->synopsis) + 23;
03185 else
03186 synopsis_size = strlen("Not available") + 23;
03187 synopsis = alloca(synopsis_size);
03188
03189 if (a->description)
03190 description_size = strlen(a->description) + 23;
03191 else
03192 description_size = strlen("Not available") + 23;
03193 description = alloca(description_size);
03194
03195 if (synopsis && description) {
03196 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
03197 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03198 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03199 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03200 term_color(synopsis,
03201 a->synopsis ? a->synopsis : "Not available",
03202 COLOR_CYAN, 0, synopsis_size);
03203 term_color(description,
03204 a->description ? a->description : "Not available",
03205 COLOR_CYAN, 0, description_size);
03206
03207 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03208 } else {
03209
03210 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
03211 "[Synopsis]\n %s\n\n"
03212 "[Description]\n%s\n",
03213 a->name,
03214 a->synopsis ? a->synopsis : "Not available",
03215 a->description ? a->description : "Not available");
03216 }
03217 }
03218 }
03219 }
03220 AST_LIST_UNLOCK(&apps);
03221
03222
03223 if (no_registered_app) {
03224 ast_cli(fd, "Your application(s) is (are) not registered\n");
03225 return RESULT_FAILURE;
03226 }
03227
03228 return RESULT_SUCCESS;
03229 }
03230
03231
03232 static int handle_show_hints(int fd, int argc, char *argv[])
03233 {
03234 struct ast_hint *hint;
03235 int num = 0;
03236 int watchers;
03237 struct ast_state_cb *watcher;
03238
03239 if (AST_LIST_EMPTY(&hints)) {
03240 ast_cli(fd, "There are no registered dialplan hints\n");
03241 return RESULT_SUCCESS;
03242 }
03243
03244 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
03245 AST_LIST_LOCK(&hints);
03246 AST_LIST_TRAVERSE(&hints, hint, list) {
03247 watchers = 0;
03248 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
03249 watchers++;
03250 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
03251 ast_get_extension_name(hint->exten),
03252 ast_get_context_name(ast_get_extension_context(hint->exten)),
03253 ast_get_extension_app(hint->exten),
03254 ast_extension_state2str(hint->laststate), watchers);
03255 num++;
03256 }
03257 ast_cli(fd, "----------------\n");
03258 ast_cli(fd, "- %d hints registered\n", num);
03259 AST_LIST_UNLOCK(&hints);
03260 return RESULT_SUCCESS;
03261 }
03262
03263
03264 static int handle_show_switches(int fd, int argc, char *argv[])
03265 {
03266 struct ast_switch *sw;
03267
03268 AST_LIST_LOCK(&switches);
03269
03270 if (AST_LIST_EMPTY(&switches)) {
03271 AST_LIST_UNLOCK(&switches);
03272 ast_cli(fd, "There are no registered alternative switches\n");
03273 return RESULT_SUCCESS;
03274 }
03275
03276 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
03277 AST_LIST_TRAVERSE(&switches, sw, list)
03278 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
03279
03280 AST_LIST_UNLOCK(&switches);
03281
03282 return RESULT_SUCCESS;
03283 }
03284
03285
03286
03287
03288 static int handle_show_applications_deprecated(int fd, int argc, char *argv[])
03289 {
03290 struct ast_app *a;
03291 int like = 0, describing = 0;
03292 int total_match = 0;
03293 int total_apps = 0;
03294
03295 AST_LIST_LOCK(&apps);
03296
03297 if (AST_LIST_EMPTY(&apps)) {
03298 ast_cli(fd, "There are no registered applications\n");
03299 AST_LIST_UNLOCK(&apps);
03300 return -1;
03301 }
03302
03303
03304 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
03305 like = 1;
03306 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
03307 describing = 1;
03308 }
03309
03310
03311 if ((!like) && (!describing)) {
03312 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
03313 } else {
03314 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
03315 }
03316
03317 AST_LIST_TRAVERSE(&apps, a, list) {
03318 int printapp = 0;
03319 total_apps++;
03320 if (like) {
03321 if (strcasestr(a->name, argv[3])) {
03322 printapp = 1;
03323 total_match++;
03324 }
03325 } else if (describing) {
03326 if (a->description) {
03327
03328 int i;
03329 printapp = 1;
03330 for (i = 3; i < argc; i++) {
03331 if (!strcasestr(a->description, argv[i])) {
03332 printapp = 0;
03333 } else {
03334 total_match++;
03335 }
03336 }
03337 }
03338 } else {
03339 printapp = 1;
03340 }
03341
03342 if (printapp) {
03343 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03344 }
03345 }
03346 if ((!like) && (!describing)) {
03347 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
03348 } else {
03349 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
03350 }
03351
03352 AST_LIST_UNLOCK(&apps);
03353
03354 return RESULT_SUCCESS;
03355 }
03356 static int handle_show_applications(int fd, int argc, char *argv[])
03357 {
03358 struct ast_app *a;
03359 int like = 0, describing = 0;
03360 int total_match = 0;
03361 int total_apps = 0;
03362
03363 AST_LIST_LOCK(&apps);
03364
03365 if (AST_LIST_EMPTY(&apps)) {
03366 ast_cli(fd, "There are no registered applications\n");
03367 AST_LIST_UNLOCK(&apps);
03368 return -1;
03369 }
03370
03371
03372 if ((argc == 5) && (!strcmp(argv[3], "like"))) {
03373 like = 1;
03374 } else if ((argc > 4) && (!strcmp(argv[3], "describing"))) {
03375 describing = 1;
03376 }
03377
03378
03379 if ((!like) && (!describing)) {
03380 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
03381 } else {
03382 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
03383 }
03384
03385 AST_LIST_TRAVERSE(&apps, a, list) {
03386 int printapp = 0;
03387 total_apps++;
03388 if (like) {
03389 if (strcasestr(a->name, argv[4])) {
03390 printapp = 1;
03391 total_match++;
03392 }
03393 } else if (describing) {
03394 if (a->description) {
03395
03396 int i;
03397 printapp = 1;
03398 for (i = 4; i < argc; i++) {
03399 if (!strcasestr(a->description, argv[i])) {
03400 printapp = 0;
03401 } else {
03402 total_match++;
03403 }
03404 }
03405 }
03406 } else {
03407 printapp = 1;
03408 }
03409
03410 if (printapp) {
03411 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03412 }
03413 }
03414 if ((!like) && (!describing)) {
03415 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
03416 } else {
03417 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
03418 }
03419
03420 AST_LIST_UNLOCK(&apps);
03421
03422 return RESULT_SUCCESS;
03423 }
03424
03425 static char *complete_show_applications_deprecated(const char *line, const char *word, int pos, int state)
03426 {
03427 static char* choices[] = { "like", "describing", NULL };
03428
03429 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
03430 }
03431
03432 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
03433 {
03434 static char* choices[] = { "like", "describing", NULL };
03435
03436 return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
03437 }
03438
03439
03440
03441
03442 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
03443 int state)
03444 {
03445 struct ast_context *c = NULL;
03446 char *ret = NULL;
03447 int which = 0;
03448 int wordlen;
03449
03450
03451 if (pos != 2)
03452 return NULL;
03453
03454 ast_lock_contexts();
03455
03456 wordlen = strlen(word);
03457
03458
03459 while ( (c = ast_walk_contexts(c)) ) {
03460 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
03461 ret = ast_strdup(ast_get_context_name(c));
03462 break;
03463 }
03464 }
03465
03466 ast_unlock_contexts();
03467
03468 return ret;
03469 }
03470
03471 struct dialplan_counters {
03472 int total_context;
03473 int total_exten;
03474 int total_prio;
03475 int context_existence;
03476 int extension_existence;
03477 };
03478
03479
03480 static void print_ext(struct ast_exten *e, char * buf, int buflen)
03481 {
03482 int prio = ast_get_extension_priority(e);
03483 if (prio == PRIORITY_HINT) {
03484 snprintf(buf, buflen, "hint: %s",
03485 ast_get_extension_app(e));
03486 } else {
03487 snprintf(buf, buflen, "%d. %s(%s)",
03488 prio, ast_get_extension_app(e),
03489 (char *)ast_get_extension_app_data(e));
03490 }
03491 }
03492
03493
03494 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[])
03495 {
03496 struct ast_context *c = NULL;
03497 int res = 0, old_total_exten = dpc->total_exten;
03498
03499 ast_lock_contexts();
03500
03501
03502 while ( (c = ast_walk_contexts(c)) ) {
03503 struct ast_exten *e;
03504 struct ast_include *i;
03505 struct ast_ignorepat *ip;
03506 char buf[256], buf2[256];
03507 int context_info_printed = 0;
03508
03509 if (context && strcmp(ast_get_context_name(c), context))
03510 continue;
03511
03512 dpc->context_existence = 1;
03513
03514 ast_lock_context(c);
03515
03516
03517
03518
03519
03520
03521
03522 if (!exten) {
03523 dpc->total_context++;
03524 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03525 ast_get_context_name(c), ast_get_context_registrar(c));
03526 context_info_printed = 1;
03527 }
03528
03529
03530 e = NULL;
03531 while ( (e = ast_walk_context_extensions(c, e)) ) {
03532 struct ast_exten *p;
03533
03534 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
03535 continue;
03536
03537 dpc->extension_existence = 1;
03538
03539
03540 if (!context_info_printed) {
03541 dpc->total_context++;
03542 if (rinclude) {
03543 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
03544 ast_get_context_name(c), ast_get_context_registrar(c));
03545 } else {
03546 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03547 ast_get_context_name(c), ast_get_context_registrar(c));
03548 }
03549 context_info_printed = 1;
03550 }
03551 dpc->total_prio++;
03552
03553
03554 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
03555
03556 print_ext(e, buf2, sizeof(buf2));
03557
03558 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
03559 ast_get_extension_registrar(e));
03560
03561 dpc->total_exten++;
03562
03563 p = e;
03564 while ( (p = ast_walk_extension_priorities(e, p)) ) {
03565 const char *el = ast_get_extension_label(p);
03566 dpc->total_prio++;
03567 if (el)
03568 snprintf(buf, sizeof(buf), " [%s]", el);
03569 else
03570 buf[0] = '\0';
03571 print_ext(p, buf2, sizeof(buf2));
03572
03573 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
03574 ast_get_extension_registrar(p));
03575 }
03576 }
03577
03578
03579 i = NULL;
03580 while ( (i = ast_walk_context_includes(c, i)) ) {
03581 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
03582 if (exten) {
03583
03584 if (includecount >= AST_PBX_MAX_STACK) {
03585 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
03586 } else {
03587 int dupe=0;
03588 int x;
03589 for (x=0;x<includecount;x++) {
03590 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
03591 dupe++;
03592 break;
03593 }
03594 }
03595 if (!dupe) {
03596 includes[includecount] = ast_get_include_name(i);
03597 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
03598 } else {
03599 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
03600 }
03601 }
03602 } else {
03603 ast_cli(fd, " Include => %-45s [%s]\n",
03604 buf, ast_get_include_registrar(i));
03605 }
03606 }
03607
03608
03609 ip = NULL;
03610 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
03611 const char *ipname = ast_get_ignorepat_name(ip);
03612 char ignorepat[AST_MAX_EXTENSION];
03613 snprintf(buf, sizeof(buf), "'%s'", ipname);
03614 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03615 if (!exten || ast_extension_match(ignorepat, exten)) {
03616 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
03617 buf, ast_get_ignorepat_registrar(ip));
03618 }
03619 }
03620 if (!rinclude) {
03621 struct ast_sw *sw = NULL;
03622 while ( (sw = ast_walk_context_switches(c, sw)) ) {
03623 snprintf(buf, sizeof(buf), "'%s/%s'",
03624 ast_get_switch_name(sw),
03625 ast_get_switch_data(sw));
03626 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
03627 buf, ast_get_switch_registrar(sw));
03628 }
03629 }
03630
03631 ast_unlock_context(c);
03632
03633
03634 if (context_info_printed)
03635 ast_cli(fd, "\r\n");
03636 }
03637 ast_unlock_contexts();
03638
03639 return (dpc->total_exten == old_total_exten) ? -1 : res;
03640 }
03641
03642 static int handle_show_dialplan(int fd, int argc, char *argv[])
03643 {
03644 char *exten = NULL, *context = NULL;
03645
03646 struct dialplan_counters counters;
03647
03648 const char *incstack[AST_PBX_MAX_STACK];
03649 memset(&counters, 0, sizeof(counters));
03650
03651 if (argc != 2 && argc != 3)
03652 return RESULT_SHOWUSAGE;
03653
03654
03655 if (argc == 3) {
03656 if (strchr(argv[2], '@')) {
03657 context = ast_strdupa(argv[2]);
03658 exten = strsep(&context, "@");
03659
03660 if (ast_strlen_zero(exten))
03661 exten = NULL;
03662 } else {
03663 context = argv[2];
03664 }
03665 if (ast_strlen_zero(context))
03666 context = NULL;
03667 }
03668
03669 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03670
03671
03672 if (context && !counters.context_existence) {
03673 ast_cli(fd, "There is no existence of '%s' context\n", context);
03674 return RESULT_FAILURE;
03675 }
03676
03677 if (exten && !counters.extension_existence) {
03678 if (context)
03679 ast_cli(fd, "There is no existence of %s@%s extension\n",
03680 exten, context);
03681 else
03682 ast_cli(fd,
03683 "There is no existence of '%s' extension in all contexts\n",
03684 exten);
03685 return RESULT_FAILURE;
03686 }
03687
03688 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
03689 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
03690 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
03691 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
03692
03693
03694 return RESULT_SUCCESS;
03695 }
03696
03697
03698 static int handle_show_globals(int fd, int argc, char *argv[])
03699 {
03700 int i = 0;
03701 struct ast_var_t *newvariable;
03702
03703 ast_mutex_lock(&globalslock);
03704 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
03705 i++;
03706 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
03707 }
03708 ast_mutex_unlock(&globalslock);
03709 ast_cli(fd, "\n -- %d variables\n", i);
03710
03711 return RESULT_SUCCESS;
03712 }
03713
03714
03715 static int handle_set_global_deprecated(int fd, int argc, char *argv[])
03716 {
03717 if (argc != 4)
03718 return RESULT_SHOWUSAGE;
03719
03720 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
03721 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
03722
03723 return RESULT_SUCCESS;
03724 }
03725
03726
03727 static int handle_set_global(int fd, int argc, char *argv[])
03728 {
03729 if (argc != 5)
03730 return RESULT_SHOWUSAGE;
03731
03732 pbx_builtin_setvar_helper(NULL, argv[3], argv[4]);
03733 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[3], argv[4]);
03734
03735 return RESULT_SUCCESS;
03736 }
03737
03738
03739
03740
03741
03742
03743 static struct ast_cli_entry cli_show_applications_deprecated = {
03744 { "show", "applications", NULL },
03745 handle_show_applications_deprecated, NULL,
03746 NULL, complete_show_applications_deprecated };
03747
03748 static struct ast_cli_entry cli_show_functions_deprecated = {
03749 { "show", "functions", NULL },
03750 handle_show_functions_deprecated, NULL,
03751 NULL };
03752
03753 static struct ast_cli_entry cli_show_switches_deprecated = {
03754 { "show", "switches", NULL },
03755 handle_show_switches, NULL,
03756 NULL };
03757
03758 static struct ast_cli_entry cli_show_hints_deprecated = {
03759 { "show", "hints", NULL },
03760 handle_show_hints, NULL,
03761 NULL };
03762
03763 static struct ast_cli_entry cli_show_globals_deprecated = {
03764 { "show", "globals", NULL },
03765 handle_show_globals, NULL,
03766 NULL };
03767
03768 static struct ast_cli_entry cli_show_function_deprecated = {
03769 { "show" , "function", NULL },
03770 handle_show_function_deprecated, NULL,
03771 NULL, complete_show_function };
03772
03773 static struct ast_cli_entry cli_show_application_deprecated = {
03774 { "show", "application", NULL },
03775 handle_show_application_deprecated, NULL,
03776 NULL, complete_show_application };
03777
03778 static struct ast_cli_entry cli_show_dialplan_deprecated = {
03779 { "show", "dialplan", NULL },
03780 handle_show_dialplan, NULL,
03781 NULL, complete_show_dialplan_context };
03782
03783 static struct ast_cli_entry cli_set_global_deprecated = {
03784 { "set", "global", NULL },
03785 handle_set_global_deprecated, NULL,
03786 NULL };
03787
03788 static struct ast_cli_entry pbx_cli[] = {
03789 { { "core", "show", "applications", NULL },
03790 handle_show_applications, "Shows registered dialplan applications",
03791 show_applications_help, complete_show_applications, &cli_show_applications_deprecated },
03792
03793 { { "core", "show", "functions", NULL },
03794 handle_show_functions, "Shows registered dialplan functions",
03795 show_functions_help, NULL, &cli_show_functions_deprecated },
03796
03797 { { "core", "show", "switches", NULL },
03798 handle_show_switches, "Show alternative switches",
03799 show_switches_help, NULL, &cli_show_switches_deprecated },
03800
03801 { { "core", "show", "hints", NULL },
03802 handle_show_hints, "Show dialplan hints",
03803 show_hints_help, NULL, &cli_show_hints_deprecated },
03804
03805 { { "core", "show", "globals", NULL },
03806 handle_show_globals, "Show global dialplan variables",
03807 show_globals_help, NULL, &cli_show_globals_deprecated },
03808
03809 { { "core", "show" , "function", NULL },
03810 handle_show_function, "Describe a specific dialplan function",
03811 show_function_help, complete_show_function, &cli_show_function_deprecated },
03812
03813 { { "core", "show", "application", NULL },
03814 handle_show_application, "Describe a specific dialplan application",
03815 show_application_help, complete_show_application, &cli_show_application_deprecated },
03816
03817 { { "core", "set", "global", NULL },
03818 handle_set_global, "Set global dialplan variable",
03819 set_global_help, NULL, &cli_set_global_deprecated },
03820
03821 { { "dialplan", "show", NULL },
03822 handle_show_dialplan, "Show dialplan",
03823 show_dialplan_help, complete_show_dialplan_context, &cli_show_dialplan_deprecated },
03824 };
03825
03826 int ast_unregister_application(const char *app)
03827 {
03828 struct ast_app *tmp;
03829
03830 AST_LIST_LOCK(&apps);
03831 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
03832 if (!strcasecmp(app, tmp->name)) {
03833 AST_LIST_REMOVE_CURRENT(&apps, list);
03834 if (option_verbose > 1)
03835 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
03836 free(tmp);
03837 break;
03838 }
03839 }
03840 AST_LIST_TRAVERSE_SAFE_END
03841 AST_LIST_UNLOCK(&apps);
03842
03843 return tmp ? 0 : -1;
03844 }
03845
03846 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
03847 {
03848 struct ast_context *tmp, **local_contexts;
03849 int length = sizeof(struct ast_context) + strlen(name) + 1;
03850
03851 if (!extcontexts) {
03852 ast_mutex_lock(&conlock);
03853 local_contexts = &contexts;
03854 } else
03855 local_contexts = extcontexts;
03856
03857 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
03858 if (!strcasecmp(tmp->name, name)) {
03859 if (!existsokay) {
03860 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
03861 tmp = NULL;
03862 }
03863 if (!extcontexts)
03864 ast_mutex_unlock(&conlock);
03865 return tmp;
03866 }
03867 }
03868 if ((tmp = ast_calloc(1, length))) {
03869 ast_mutex_init(&tmp->lock);
03870 ast_mutex_init(&tmp->macrolock);
03871 strcpy(tmp->name, name);
03872 tmp->root = NULL;
03873 tmp->registrar = registrar;
03874 tmp->next = *local_contexts;
03875 tmp->includes = NULL;
03876 tmp->ignorepats = NULL;
03877 *local_contexts = tmp;
03878 if (option_debug)
03879 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
03880 if (option_verbose > 2)
03881 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
03882 }
03883
03884 if (!extcontexts)
03885 ast_mutex_unlock(&conlock);
03886 return tmp;
03887 }
03888
03889 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03890 {
03891 return __ast_context_create(extcontexts, name, registrar, 0);
03892 }
03893
03894 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03895 {
03896 return __ast_context_create(extcontexts, name, registrar, 1);
03897 }
03898 void __ast_context_destroy(struct ast_context *con, const char *registrar);
03899
03900 struct store_hint {
03901 char *context;
03902 char *exten;
03903 struct ast_state_cb *callbacks;
03904 int laststate;
03905 AST_LIST_ENTRY(store_hint) list;
03906 char data[1];
03907 };
03908
03909 AST_LIST_HEAD(store_hints, store_hint);
03910
03911
03912 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
03913 {
03914 struct ast_context *tmp, *lasttmp = NULL;
03915 struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
03916 struct store_hint *this;
03917 struct ast_hint *hint;
03918 struct ast_exten *exten;
03919 int length;
03920 struct ast_state_cb *thiscb, *prevcb;
03921
03922
03923
03924
03925
03926
03927
03928
03929
03930 ast_mutex_lock(&conlock);
03931 AST_LIST_LOCK(&hints);
03932
03933
03934 AST_LIST_TRAVERSE(&hints, hint, list) {
03935 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
03936 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
03937 if (!(this = ast_calloc(1, length)))
03938 continue;
03939 this->callbacks = hint->callbacks;
03940 hint->callbacks = NULL;
03941 this->laststate = hint->laststate;
03942 this->context = this->data;
03943 strcpy(this->data, hint->exten->parent->name);
03944 this->exten = this->data + strlen(this->context) + 1;
03945 strcpy(this->exten, hint->exten->exten);
03946 AST_LIST_INSERT_HEAD(&store, this, list);
03947 }
03948 }
03949
03950 tmp = *extcontexts;
03951 if (registrar) {
03952
03953 if (option_debug)
03954 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
03955 __ast_context_destroy(NULL,registrar);
03956 while (tmp) {
03957 lasttmp = tmp;
03958 tmp = tmp->next;
03959 }
03960 } else {
03961
03962 while (tmp) {
03963 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
03964 __ast_context_destroy(tmp,tmp->registrar);
03965 lasttmp = tmp;
03966 tmp = tmp->next;
03967 }
03968 }
03969 if (lasttmp) {
03970 lasttmp->next = contexts;
03971 contexts = *extcontexts;
03972 *extcontexts = NULL;
03973 } else
03974 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
03975
03976
03977
03978
03979 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
03980 exten = ast_hint_extension(NULL, this->context, this->exten);
03981
03982 AST_LIST_TRAVERSE(&hints, hint, list) {
03983 if (hint->exten == exten)
03984 break;
03985 }
03986 if (!exten || !hint) {
03987
03988 prevcb = NULL;
03989 thiscb = this->callbacks;
03990 while (thiscb) {
03991 prevcb = thiscb;
03992 thiscb = thiscb->next;
03993 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
03994 free(prevcb);
03995 }
03996 } else {
03997 thiscb = this->callbacks;
03998 while (thiscb->next)
03999 thiscb = thiscb->next;
04000 thiscb->next = hint->callbacks;
04001 hint->callbacks = this->callbacks;
04002 hint->laststate = this->laststate;
04003 }
04004 free(this);
04005 }
04006
04007 AST_LIST_UNLOCK(&hints);
04008 ast_mutex_unlock(&conlock);
04009
04010 return;
04011 }
04012
04013
04014
04015
04016
04017
04018 int ast_context_add_include(const char *context, const char *include, const char *registrar)
04019 {
04020 int ret = -1;
04021 struct ast_context *c = find_context_locked(context);
04022
04023 if (c) {
04024 ret = ast_context_add_include2(c, include, registrar);
04025 ast_unlock_contexts();
04026 }
04027 return ret;
04028 }
04029
04030
04031
04032
04033
04034 static int lookup_name(const char *s, char *const names[], int max)
04035 {
04036 int i;
04037
04038 if (names) {
04039 for (i = 0; names[i]; i++) {
04040 if (!strcasecmp(s, names[i]))
04041 return i+1;
04042 }
04043 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
04044 return i;
04045 }
04046 return 0;
04047 }
04048
04049
04050
04051
04052 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
04053 {
04054 int s, e;
04055 unsigned int mask = 0;
04056
04057
04058 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
04059 s = 0;
04060 e = max - 1;
04061 } else {
04062
04063 char *c = strchr(src, '-');
04064 if (c)
04065 *c++ = '\0';
04066
04067 s = lookup_name(src, names, max);
04068 if (!s) {
04069 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
04070 return 0;
04071 }
04072 s--;
04073 if (c) {
04074 e = lookup_name(c, names, max);
04075 if (!e) {
04076 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
04077 return 0;
04078 }
04079 e--;
04080 } else
04081 e = s;
04082 }
04083
04084 mask = 1 << e;
04085 while (s != e) {
04086 if (s >= max) {
04087 s = 0;
04088 mask |= (1 << s);
04089 } else {
04090 mask |= (1 << s);
04091 s++;
04092 }
04093 }
04094 return mask;
04095 }
04096
04097
04098 static void get_timerange(struct ast_timing *i, char *times)
04099 {
04100 char *e;
04101 int x;
04102 int s1, s2;
04103 int e1, e2;
04104
04105
04106
04107 memset(i->minmask, 0, sizeof(i->minmask));
04108
04109
04110
04111 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
04112 for (x=0; x<24; x++)
04113 i->minmask[x] = 0x3fffffff;
04114 return;
04115 }
04116
04117 e = strchr(times, '-');
04118 if (!e) {
04119 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
04120 return;
04121 }
04122 *e++ = '\0';
04123
04124 while (*e && !isdigit(*e))
04125 e++;
04126 if (!*e) {
04127 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
04128 return;
04129 }
04130 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
04131 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
04132 return;
04133 }
04134 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
04135 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
04136 return;
04137 }
04138
04139 #if 1
04140 s1 = s1 * 30 + s2/2;
04141 if ((s1 < 0) || (s1 >= 24*30)) {
04142 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
04143 return;
04144 }
04145 e1 = e1 * 30 + e2/2;
04146 if ((e1 < 0) || (e1 >= 24*30)) {
04147 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
04148 return;
04149 }
04150
04151 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
04152 i->minmask[x/30] |= (1 << (x % 30));
04153 }
04154
04155 i->minmask[x/30] |= (1 << (x % 30));
04156 #else
04157 for (cth=0; cth<24; cth++) {
04158
04159 i->minmask[cth] = 0;
04160 for (ctm=0; ctm<30; ctm++) {
04161 if (
04162
04163 (((cth == s1) && (ctm >= s2)) &&
04164 ((cth < e1)))
04165
04166 || (((cth == s1) && (ctm >= s2)) &&
04167 ((cth == e1) && (ctm <= e2)))
04168
04169 || ((cth > s1) &&
04170 (cth < e1))
04171
04172 || ((cth > s1) &&
04173 ((cth == e1) && (ctm <= e2)))
04174 )
04175 i->minmask[cth] |= (1 << (ctm / 2));
04176 }
04177 }
04178 #endif
04179
04180 return;
04181 }
04182
04183 static char *days[] =
04184 {
04185 "sun",
04186 "mon",
04187 "tue",
04188 "wed",
04189 "thu",
04190 "fri",
04191 "sat",
04192 NULL,
04193 };
04194
04195 static char *months[] =
04196 {
04197 "jan",
04198 "feb",
04199 "mar",
04200 "apr",
04201 "may",
04202 "jun",
04203 "jul",
04204 "aug",
04205 "sep",
04206 "oct",
04207 "nov",
04208 "dec",
04209 NULL,
04210 };
04211
04212 int ast_build_timing(struct ast_timing *i, const char *info_in)
04213 {
04214 char info_save[256];
04215 char *info;
04216
04217
04218 if (ast_strlen_zero(info_in))
04219 return 0;
04220
04221 ast_copy_string(info_save, info_in, sizeof(info_save));
04222 info = info_save;
04223
04224 i->monthmask = 0xfff;
04225 i->daymask = 0x7fffffffU;
04226 i->dowmask = 0x7f;
04227
04228 get_timerange(i, strsep(&info, "|"));
04229 if (info)
04230 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
04231 if (info)
04232 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
04233 if (info)
04234 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
04235 return 1;
04236 }
04237
04238 int ast_check_timing(const struct ast_timing *i)
04239 {
04240 struct tm tm;
04241 time_t t = time(NULL);
04242
04243 ast_localtime(&t, &tm, NULL);
04244
04245
04246 if (!(i->monthmask & (1 << tm.tm_mon)))
04247 return 0;
04248
04249
04250
04251 if (!(i->daymask & (1 << (tm.tm_mday-1))))
04252 return 0;
04253
04254
04255 if (!(i->dowmask & (1 << tm.tm_wday)))
04256 return 0;
04257
04258
04259 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
04260 ast_log(LOG_WARNING, "Insane time...\n");
04261 return 0;
04262 }
04263
04264
04265
04266 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
04267 return 0;
04268
04269
04270 return 1;
04271 }
04272
04273
04274
04275
04276
04277
04278
04279
04280 int ast_context_add_include2(struct ast_context *con, const char *value,
04281 const char *registrar)
04282 {
04283 struct ast_include *new_include;
04284 char *c;
04285 struct ast_include *i, *il = NULL;
04286 int length;
04287 char *p;
04288
04289 length = sizeof(struct ast_include);
04290 length += 2 * (strlen(value) + 1);
04291
04292
04293 if (!(new_include = ast_calloc(1, length)))
04294 return -1;
04295
04296
04297
04298 p = new_include->stuff;
04299 new_include->name = p;
04300 strcpy(p, value);
04301 p += strlen(value) + 1;
04302 new_include->rname = p;
04303 strcpy(p, value);
04304
04305 if ( (c = strchr(p, '|')) ) {
04306 *c++ = '\0';
04307 new_include->hastime = ast_build_timing(&(new_include->timing), c);
04308 }
04309 new_include->next = NULL;
04310 new_include->registrar = registrar;
04311
04312 ast_mutex_lock(&con->lock);
04313
04314
04315 for (i = con->includes; i; i = i->next) {
04316 if (!strcasecmp(i->name, new_include->name)) {
04317 free(new_include);
04318 ast_mutex_unlock(&con->lock);
04319 errno = EEXIST;
04320 return -1;
04321 }
04322 il = i;
04323 }
04324
04325
04326 if (il)
04327 il->next = new_include;
04328 else
04329 con->includes = new_include;
04330 if (option_verbose > 2)
04331 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04332 ast_mutex_unlock(&con->lock);
04333
04334 return 0;
04335 }
04336
04337
04338
04339
04340
04341
04342 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
04343 {
04344 int ret = -1;
04345 struct ast_context *c = find_context_locked(context);
04346
04347 if (c) {
04348 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
04349 ast_unlock_contexts();
04350 }
04351 return ret;
04352 }
04353
04354
04355
04356
04357
04358
04359
04360
04361 int ast_context_add_switch2(struct ast_context *con, const char *value,
04362 const char *data, int eval, const char *registrar)
04363 {
04364 struct ast_sw *new_sw;
04365 struct ast_sw *i;
04366 int length;
04367 char *p;
04368
04369 length = sizeof(struct ast_sw);
04370 length += strlen(value) + 1;
04371 if (data)
04372 length += strlen(data);
04373 length++;
04374 if (eval) {
04375
04376 length += SWITCH_DATA_LENGTH;
04377 length++;
04378 }
04379
04380
04381 if (!(new_sw = ast_calloc(1, length)))
04382 return -1;
04383
04384 p = new_sw->stuff;
04385 new_sw->name = p;
04386 strcpy(new_sw->name, value);
04387 p += strlen(value) + 1;
04388 new_sw->data = p;
04389 if (data) {
04390 strcpy(new_sw->data, data);
04391 p += strlen(data) + 1;
04392 } else {
04393 strcpy(new_sw->data, "");
04394 p++;
04395 }
04396 if (eval)
04397 new_sw->tmpdata = p;
04398 new_sw->eval = eval;
04399 new_sw->registrar = registrar;
04400
04401
04402 ast_mutex_lock(&con->lock);
04403
04404
04405 AST_LIST_TRAVERSE(&con->alts, i, list) {
04406 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04407 free(new_sw);
04408 ast_mutex_unlock(&con->lock);
04409 errno = EEXIST;
04410 return -1;
04411 }
04412 }
04413
04414
04415 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
04416
04417 if (option_verbose > 2)
04418 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04419
04420 ast_mutex_unlock(&con->lock);
04421
04422 return 0;
04423 }
04424
04425
04426
04427
04428
04429 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
04430 {
04431 int ret = -1;
04432 struct ast_context *c = find_context_locked(context);
04433
04434 if (c) {
04435 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
04436 ast_unlock_contexts();
04437 }
04438 return ret;
04439 }
04440
04441 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
04442 {
04443 struct ast_ignorepat *ip, *ipl = NULL;
04444
04445 ast_mutex_lock(&con->lock);
04446
04447 for (ip = con->ignorepats; ip; ip = ip->next) {
04448 if (!strcmp(ip->pattern, ignorepat) &&
04449 (!registrar || (registrar == ip->registrar))) {
04450 if (ipl) {
04451 ipl->next = ip->next;
04452 free(ip);
04453 } else {
04454 con->ignorepats = ip->next;
04455 free(ip);
04456 }
04457 ast_mutex_unlock(&con->lock);
04458 return 0;
04459 }
04460 ipl = ip;
04461 }
04462
04463 ast_mutex_unlock(&con->lock);
04464 errno = EINVAL;
04465 return -1;
04466 }
04467
04468
04469
04470
04471
04472 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
04473 {
04474 int ret = -1;
04475 struct ast_context *c = find_context_locked(context);
04476
04477 if (c) {
04478 ret = ast_context_add_ignorepat2(c, value, registrar);
04479 ast_unlock_contexts();
04480 }
04481 return ret;
04482 }
04483
04484 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04485 {
04486 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04487 int length;
04488 length = sizeof(struct ast_ignorepat);
04489 length += strlen(value) + 1;
04490 if (!(ignorepat = ast_calloc(1, length)))
04491 return -1;
04492
04493
04494
04495 strcpy((char *)ignorepat->pattern, value);
04496 ignorepat->next = NULL;
04497 ignorepat->registrar = registrar;
04498 ast_mutex_lock(&con->lock);
04499 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
04500 ignorepatl = ignorepatc;
04501 if (!strcasecmp(ignorepatc->pattern, value)) {
04502
04503 ast_mutex_unlock(&con->lock);
04504 errno = EEXIST;
04505 return -1;
04506 }
04507 }
04508 if (ignorepatl)
04509 ignorepatl->next = ignorepat;
04510 else
04511 con->ignorepats = ignorepat;
04512 ast_mutex_unlock(&con->lock);
04513 return 0;
04514
04515 }
04516
04517 int ast_ignore_pattern(const char *context, const char *pattern)
04518 {
04519 struct ast_context *con = ast_context_find(context);
04520 if (con) {
04521 struct ast_ignorepat *pat;
04522 for (pat = con->ignorepats; pat; pat = pat->next) {
04523 if (ast_extension_match(pat->pattern, pattern))
04524 return 1;
04525 }
04526 }
04527
04528 return 0;
04529 }
04530
04531
04532
04533
04534
04535
04536 int ast_add_extension(const char *context, int replace, const char *extension,
04537 int priority, const char *label, const char *callerid,
04538 const char *application, void *data, void (*datad)(void *), const char *registrar)
04539 {
04540 int ret = -1;
04541 struct ast_context *c = find_context_locked(context);
04542
04543 if (c) {
04544 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
04545 application, data, datad, registrar);
04546 ast_unlock_contexts();
04547 }
04548 return ret;
04549 }
04550
04551 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04552 {
04553 if (!chan)
04554 return -1;
04555
04556 if (!ast_strlen_zero(context))
04557 ast_copy_string(chan->context, context, sizeof(chan->context));
04558 if (!ast_strlen_zero(exten))
04559 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
04560 if (priority > -1) {
04561 chan->priority = priority;
04562
04563 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
04564 chan->priority--;
04565 }
04566
04567 return 0;
04568 }
04569
04570 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04571 {
04572 int res = 0;
04573
04574 ast_channel_lock(chan);
04575
04576 if (chan->pbx) {
04577 ast_explicit_goto(chan, context, exten, priority);
04578 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
04579 } else {
04580
04581
04582
04583 struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
04584 if (chan->cdr) {
04585 tmpchan->cdr = ast_cdr_dup(chan->cdr);
04586 }
04587 if (!tmpchan)
04588 res = -1;
04589 else {
04590
04591 tmpchan->readformat = chan->readformat;
04592 tmpchan->writeformat = chan->writeformat;
04593
04594 ast_explicit_goto(tmpchan,
04595 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
04596
04597
04598 ast_channel_masquerade(tmpchan, chan);
04599
04600
04601 ast_channel_lock(tmpchan);
04602 ast_do_masquerade(tmpchan);
04603 ast_channel_unlock(tmpchan);
04604
04605 if (ast_pbx_start(tmpchan)) {
04606 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
04607 ast_hangup(tmpchan);
04608 res = -1;
04609 }
04610 }
04611 }
04612 ast_channel_unlock(chan);
04613 return res;
04614 }
04615
04616 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
04617 {
04618 struct ast_channel *chan;
04619 int res = -1;
04620
04621 chan = ast_get_channel_by_name_locked(channame);
04622 if (chan) {
04623 res = ast_async_goto(chan, context, exten, priority);
04624 ast_channel_unlock(chan);
04625 }
04626 return res;
04627 }
04628
04629
04630 static int ext_strncpy(char *dst, const char *src, int len)
04631 {
04632 int count=0;
04633
04634 while (*src && (count < len - 1)) {
04635 switch(*src) {
04636 case ' ':
04637
04638
04639
04640 break;
04641 default:
04642 *dst = *src;
04643 dst++;
04644 }
04645 src++;
04646 count++;
04647 }
04648 *dst = '\0';
04649
04650 return count;
04651 }
04652
04653
04654
04655
04656 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
04657 struct ast_exten *el, struct ast_exten *e, int replace)
04658 {
04659 struct ast_exten *ep;
04660
04661 for (ep = NULL; e ; ep = e, e = e->peer) {
04662 if (e->priority >= tmp->priority)
04663 break;
04664 }
04665 if (!e) {
04666 ep->peer = tmp;
04667 return 0;
04668 }
04669 if (e->priority == tmp->priority) {
04670
04671
04672 if (!replace) {
04673 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04674 if (tmp->datad)
04675 tmp->datad(tmp->data);
04676 free(tmp);
04677 return -1;
04678 }
04679
04680
04681
04682 tmp->next = e->next;
04683 tmp->peer = e->peer;
04684 if (ep)
04685 ep->peer = tmp;
04686 else if (el)
04687 el->next = tmp;
04688 else
04689 con->root = tmp;
04690 if (tmp->priority == PRIORITY_HINT)
04691 ast_change_hint(e,tmp);
04692
04693 if (e->datad)
04694 e->datad(e->data);
04695 free(e);
04696 } else {
04697 tmp->peer = e;
04698 tmp->next = e->next;
04699 if (ep)
04700 ep->peer = tmp;
04701 else {
04702 if (el)
04703 el->next = tmp;
04704 else
04705 con->root = tmp;
04706 e->next = NULL;
04707 }
04708
04709 if (tmp->priority == PRIORITY_HINT)
04710 ast_add_hint(tmp);
04711 }
04712 return 0;
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
04739
04740 int ast_add_extension2(struct ast_context *con,
04741 int replace, const char *extension, int priority, const char *label, const char *callerid,
04742 const char *application, void *data, void (*datad)(void *),
04743 const char *registrar)
04744 {
04745
04746
04747
04748
04749
04750
04751 struct ast_exten *tmp, *e, *el = NULL;
04752 int res;
04753 int length;
04754 char *p;
04755 char expand_buf[VAR_BUF_SIZE] = { 0, };
04756
04757
04758
04759
04760 ast_mutex_lock(&globalslock);
04761 if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04762 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04763 application = expand_buf;
04764 }
04765 ast_mutex_unlock(&globalslock);
04766
04767 length = sizeof(struct ast_exten);
04768 length += strlen(extension) + 1;
04769 length += strlen(application) + 1;
04770 if (label)
04771 length += strlen(label) + 1;
04772 if (callerid)
04773 length += strlen(callerid) + 1;
04774 else
04775 length ++;
04776
04777
04778 if (!(tmp = ast_calloc(1, length)))
04779 return -1;
04780
04781
04782 p = tmp->stuff;
04783 if (label) {
04784 tmp->label = p;
04785 strcpy(p, label);
04786 p += strlen(label) + 1;
04787 }
04788 tmp->exten = p;
04789 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
04790 tmp->priority = priority;
04791 tmp->cidmatch = p;
04792 if (callerid) {
04793 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
04794 tmp->matchcid = 1;
04795 } else {
04796 *p++ = '\0';
04797 tmp->matchcid = 0;
04798 }
04799 tmp->app = p;
04800 strcpy(p, application);
04801 tmp->parent = con;
04802 tmp->data = data;
04803 tmp->datad = datad;
04804 tmp->registrar = registrar;
04805
04806 ast_mutex_lock(&con->lock);
04807 res = 0;
04808 for (e = con->root; e; el = e, e = e->next) {
04809 res = ext_cmp(e->exten, extension);
04810 if (res == 0) {
04811 if (!e->matchcid && !tmp->matchcid)
04812 res = 0;
04813 else if (tmp->matchcid && !e->matchcid)
04814 res = 1;
04815 else if (e->matchcid && !tmp->matchcid)
04816 res = -1;
04817 else
04818 res = strcasecmp(e->cidmatch, tmp->cidmatch);
04819 }
04820 if (res >= 0)
04821 break;
04822 }
04823 if (e && res == 0) {
04824 res = add_pri(con, tmp, el, e, replace);
04825 ast_mutex_unlock(&con->lock);
04826 if (res < 0) {
04827 errno = EEXIST;
04828 return 0;
04829 }
04830 } else {
04831
04832
04833
04834
04835 tmp->next = e;
04836 if (el)
04837 el->next = tmp;
04838 else
04839 con->root = tmp;
04840 ast_mutex_unlock(&con->lock);
04841 if (tmp->priority == PRIORITY_HINT)
04842 ast_add_hint(tmp);
04843 }
04844 if (option_debug) {
04845 if (tmp->matchcid) {
04846 if (option_debug)
04847 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
04848 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04849 } else {
04850 if (option_debug)
04851 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
04852 tmp->exten, tmp->priority, con->name);
04853 }
04854 }
04855 if (option_verbose > 2) {
04856 if (tmp->matchcid) {
04857 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
04858 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04859 } else {
04860 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
04861 tmp->exten, tmp->priority, con->name);
04862 }
04863 }
04864 return 0;
04865 }
04866
04867 struct async_stat {
04868 pthread_t p;
04869 struct ast_channel *chan;
04870 char context[AST_MAX_CONTEXT];
04871 char exten[AST_MAX_EXTENSION];
04872 int priority;
04873 int timeout;
04874 char app[AST_MAX_EXTENSION];
04875 char appdata[1024];
04876 };
04877
04878 static void *async_wait(void *data)
04879 {
04880 struct async_stat *as = data;
04881 struct ast_channel *chan = as->chan;
04882 int timeout = as->timeout;
04883 int res;
04884 struct ast_frame *f;
04885 struct ast_app *app;
04886
04887 while (timeout && (chan->_state != AST_STATE_UP)) {
04888 res = ast_waitfor(chan, timeout);
04889 if (res < 1)
04890 break;
04891 if (timeout > -1)
04892 timeout = res;
04893 f = ast_read(chan);
04894 if (!f)
04895 break;
04896 if (f->frametype == AST_FRAME_CONTROL) {
04897 if ((f->subclass == AST_CONTROL_BUSY) ||
04898 (f->subclass == AST_CONTROL_CONGESTION) ) {
04899 ast_frfree(f);
04900 break;
04901 }
04902 }
04903 ast_frfree(f);
04904 }
04905 if (chan->_state == AST_STATE_UP) {
04906 if (!ast_strlen_zero(as->app)) {
04907 app = pbx_findapp(as->app);
04908 if (app) {
04909 if (option_verbose > 2)
04910 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04911 pbx_exec(chan, app, as->appdata);
04912 } else
04913 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04914 } else {
04915 if (!ast_strlen_zero(as->context))
04916 ast_copy_string(chan->context, as->context, sizeof(chan->context));
04917 if (!ast_strlen_zero(as->exten))
04918 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
04919 if (as->priority > 0)
04920 chan->priority = as->priority;
04921
04922 if (ast_pbx_run(chan)) {
04923 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04924 } else {
04925
04926 chan = NULL;
04927 }
04928 }
04929 }
04930 free(as);
04931 if (chan)
04932 ast_hangup(chan);
04933 return NULL;
04934 }
04935
04936
04937
04938
04939
04940
04941 static int ast_pbx_outgoing_cdr_failed(void)
04942 {
04943
04944 struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0);
04945
04946 if (!chan)
04947 return -1;
04948
04949 if (!chan->cdr) {
04950
04951 ast_channel_free(chan);
04952 return -1;
04953 }
04954
04955
04956 ast_cdr_init(chan->cdr, chan);
04957 ast_cdr_start(chan->cdr);
04958 ast_cdr_end(chan->cdr);
04959 ast_cdr_failed(chan->cdr);
04960 ast_cdr_detach(chan->cdr);
04961 ast_channel_free(chan);
04962
04963 return 0;
04964 }
04965
04966 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)
04967 {
04968 struct ast_channel *chan;
04969 struct async_stat *as;
04970 int res = -1, cdr_res = -1;
04971 struct outgoing_helper oh;
04972 pthread_attr_t attr;
04973
04974 if (sync) {
04975 LOAD_OH(oh);
04976 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
04977 if (channel) {
04978 *channel = chan;
04979 if (chan)
04980 ast_channel_lock(chan);
04981 }
04982 if (chan) {
04983 if (chan->_state == AST_STATE_UP) {
04984 res = 0;
04985 if (option_verbose > 3)
04986 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
04987
04988 if (sync > 1) {
04989 if (channel)
04990 ast_channel_unlock(chan);
04991 if (ast_pbx_run(chan)) {
04992 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
04993 if (channel)
04994 *channel = NULL;
04995 ast_hangup(chan);
04996 res = -1;
04997 }
04998 } else {
04999 if (ast_pbx_start(chan)) {
05000 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05001 if (channel) {
05002 *channel = NULL;
05003 ast_channel_unlock(chan);
05004 }
05005 ast_hangup(chan);
05006 res = -1;
05007 }
05008 }
05009 } else {
05010 if (option_verbose > 3)
05011 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05012
05013 if (chan->cdr) {
05014
05015
05016 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05017 ast_cdr_failed(chan->cdr);
05018 }
05019
05020 if (channel) {
05021 *channel = NULL;
05022 ast_channel_unlock(chan);
05023 }
05024 ast_hangup(chan);
05025 }
05026 }
05027
05028 if (res < 0) {
05029 if (*reason == 0) {
05030
05031 cdr_res = ast_pbx_outgoing_cdr_failed();
05032 if (cdr_res != 0) {
05033 res = cdr_res;
05034 goto outgoing_exten_cleanup;
05035 }
05036 }
05037
05038
05039
05040 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05041 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
05042 if (chan) {
05043 if (!ast_strlen_zero(context))
05044 ast_copy_string(chan->context, context, sizeof(chan->context));
05045 set_ext_pri(chan, "failed", 1);
05046 ast_set_variables(chan, vars);
05047 if (account)
05048 ast_cdr_setaccount(chan, account);
05049 ast_pbx_run(chan);
05050 }
05051 }
05052 }
05053 } else {
05054 if (!(as = ast_calloc(1, sizeof(*as)))) {
05055 res = -1;
05056 goto outgoing_exten_cleanup;
05057 }
05058 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05059 if (channel) {
05060 *channel = chan;
05061 if (chan)
05062 ast_channel_lock(chan);
05063 }
05064 if (!chan) {
05065 free(as);
05066 res = -1;
05067 goto outgoing_exten_cleanup;
05068 }
05069 as->chan = chan;
05070 ast_copy_string(as->context, context, sizeof(as->context));
05071 set_ext_pri(as->chan, exten, priority);
05072 as->timeout = timeout;
05073 ast_set_variables(chan, vars);
05074 if (account)
05075 ast_cdr_setaccount(chan, account);
05076 pthread_attr_init(&attr);
05077 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05078 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05079 ast_log(LOG_WARNING, "Failed to start async wait\n");
05080 free(as);
05081 if (channel) {
05082 *channel = NULL;
05083 ast_channel_unlock(chan);
05084 }
05085 ast_hangup(chan);
05086 res = -1;
05087 pthread_attr_destroy(&attr);
05088 goto outgoing_exten_cleanup;
05089 }
05090 pthread_attr_destroy(&attr);
05091 res = 0;
05092 }
05093 outgoing_exten_cleanup:
05094 ast_variables_destroy(vars);
05095 return res;
05096 }
05097
05098 struct app_tmp {
05099 char app[256];
05100 char data[256];
05101 struct ast_channel *chan;
05102 pthread_t t;
05103 };
05104
05105
05106 static void *ast_pbx_run_app(void *data)
05107 {
05108 struct app_tmp *tmp = data;
05109 struct ast_app *app;
05110 app = pbx_findapp(tmp->app);
05111 if (app) {
05112 if (option_verbose > 3)
05113 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05114 pbx_exec(tmp->chan, app, tmp->data);
05115 } else
05116 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05117 ast_hangup(tmp->chan);
05118 free(tmp);
05119 return NULL;
05120 }
05121
05122 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)
05123 {
05124 struct ast_channel *chan;
05125 struct app_tmp *tmp;
05126 int res = -1, cdr_res = -1;
05127 struct outgoing_helper oh;
05128 pthread_attr_t attr;
05129
05130 memset(&oh, 0, sizeof(oh));
05131 oh.vars = vars;
05132 oh.account = account;
05133
05134 if (locked_channel)
05135 *locked_channel = NULL;
05136 if (ast_strlen_zero(app)) {
05137 res = -1;
05138 goto outgoing_app_cleanup;
05139 }
05140 if (sync) {
05141 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05142 if (chan) {
05143 if (chan->cdr) {
05144 ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
05145 } else {
05146 chan->cdr = ast_cdr_alloc();
05147 if(!chan->cdr) {
05148
05149 free(chan->pbx);
05150 res = -1;
05151 goto outgoing_app_cleanup;
05152 }
05153
05154 ast_cdr_init(chan->cdr, chan);
05155 ast_cdr_start(chan->cdr);
05156 }
05157 ast_set_variables(chan, vars);
05158 if (account)
05159 ast_cdr_setaccount(chan, account);
05160 if (chan->_state == AST_STATE_UP) {
05161 res = 0;
05162 if (option_verbose > 3)
05163 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05164 tmp = ast_calloc(1, sizeof(*tmp));
05165 if (!tmp)
05166 res = -1;
05167 else {
05168 ast_copy_string(tmp->app, app, sizeof(tmp->app));
05169 if (appdata)
05170 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05171 tmp->chan = chan;
05172 if (sync > 1) {
05173 if (locked_channel)
05174 ast_channel_unlock(chan);
05175 ast_pbx_run_app(tmp);
05176 } else {
05177 pthread_attr_init(&attr);
05178 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05179 if (locked_channel)
05180 ast_channel_lock(chan);
05181 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05182 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05183 free(tmp);
05184 if (locked_channel)
05185 ast_channel_unlock(chan);
05186 ast_hangup(chan);
05187 res = -1;
05188 } else {
05189 if (locked_channel)
05190 *locked_channel = chan;
05191 }
05192 pthread_attr_destroy(&attr);
05193 }
05194 }
05195 } else {
05196 if (option_verbose > 3)
05197 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05198 if (chan->cdr) {
05199
05200
05201 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05202 ast_cdr_failed(chan->cdr);
05203 }
05204 ast_hangup(chan);
05205 }
05206 }
05207
05208 if (res < 0) {
05209 if (*reason == 0) {
05210
05211 cdr_res = ast_pbx_outgoing_cdr_failed();
05212 if (cdr_res != 0) {
05213 res = cdr_res;
05214 goto outgoing_app_cleanup;
05215 }
05216 }
05217 }
05218
05219 } else {
05220 struct async_stat *as;
05221 if (!(as = ast_calloc(1, sizeof(*as)))) {
05222 res = -1;
05223 goto outgoing_app_cleanup;
05224 }
05225 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05226 if (!chan) {
05227 free(as);
05228 res = -1;
05229 goto outgoing_app_cleanup;
05230 }
05231 as->chan = chan;
05232 ast_copy_string(as->app, app, sizeof(as->app));
05233 if (appdata)
05234 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
05235 as->timeout = timeout;
05236 ast_set_variables(chan, vars);
05237 if (account)
05238 ast_cdr_setaccount(chan, account);
05239
05240 pthread_attr_init(&attr);
05241 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05242 if (locked_channel)
05243 ast_channel_lock(chan);
05244 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05245 ast_log(LOG_WARNING, "Failed to start async wait\n");
05246 free(as);
05247 if (locked_channel)
05248 ast_channel_unlock(chan);
05249 ast_hangup(chan);
05250 res = -1;
05251 pthread_attr_destroy(&attr);
05252 goto outgoing_app_cleanup;
05253 } else {
05254 if (locked_channel)
05255 *locked_channel = chan;
05256 }
05257 pthread_attr_destroy(&attr);
05258 res = 0;
05259 }
05260 outgoing_app_cleanup:
05261 ast_variables_destroy(vars);
05262 return res;
05263 }
05264
05265 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05266 {
05267 struct ast_context *tmp, *tmpl=NULL;
05268 struct ast_include *tmpi;
05269 struct ast_sw *sw;
05270 struct ast_exten *e, *el, *en;
05271 struct ast_ignorepat *ipi;
05272
05273 ast_mutex_lock(&conlock);
05274 for (tmp = contexts; tmp; ) {
05275 struct ast_context *next;
05276 for (; tmp; tmpl = tmp, tmp = tmp->next) {
05277 if (option_debug)
05278 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
05279 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
05280 (!con || !strcasecmp(tmp->name, con->name)) )
05281 break;
05282 }
05283 if (!tmp)
05284 break;
05285 ast_mutex_lock(&tmp->lock);
05286 if (option_debug)
05287 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
05288 next = tmp->next;
05289 if (tmpl)
05290 tmpl->next = next;
05291 else
05292 contexts = next;
05293
05294
05295 ast_mutex_unlock(&tmp->lock);
05296 for (tmpi = tmp->includes; tmpi; ) {
05297 struct ast_include *tmpil = tmpi;
05298 tmpi = tmpi->next;
05299 free(tmpil);
05300 }
05301 for (ipi = tmp->ignorepats; ipi; ) {
05302 struct ast_ignorepat *ipl = ipi;
05303 ipi = ipi->next;
05304 free(ipl);
05305 }
05306 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
05307 free(sw);
05308 for (e = tmp->root; e;) {
05309 for (en = e->peer; en;) {
05310 el = en;
05311 en = en->peer;
05312 destroy_exten(el);
05313 }
05314 el = e;
05315 e = e->next;
05316 destroy_exten(el);
05317 }
05318 ast_mutex_destroy(&tmp->lock);
05319 free(tmp);
05320
05321 tmp = con ? NULL : next;
05322 }
05323 ast_mutex_unlock(&conlock);
05324 }
05325
05326 void ast_context_destroy(struct ast_context *con, const char *registrar)
05327 {
05328 __ast_context_destroy(con,registrar);
05329 }
05330
05331 static void wait_for_hangup(struct ast_channel *chan, void *data)
05332 {
05333 int res;
05334 struct ast_frame *f;
05335 int waittime;
05336
05337 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
05338 waittime = -1;
05339 if (waittime > -1) {
05340 ast_safe_sleep(chan, waittime * 1000);
05341 } else do {
05342 res = ast_waitfor(chan, -1);
05343 if (res < 0)
05344 return;
05345 f = ast_read(chan);
05346 if (f)
05347 ast_frfree(f);
05348 } while(f);
05349 }
05350
05351
05352
05353
05354 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05355 {
05356 ast_indicate(chan, AST_CONTROL_PROGRESS);
05357 return 0;
05358 }
05359
05360
05361
05362
05363 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05364 {
05365 ast_indicate(chan, AST_CONTROL_RINGING);
05366 return 0;
05367 }
05368
05369
05370
05371
05372 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05373 {
05374 ast_indicate(chan, AST_CONTROL_BUSY);
05375
05376
05377 if (chan->_state != AST_STATE_UP)
05378 ast_setstate(chan, AST_STATE_BUSY);
05379 if( ast_strlen_zero(data) )
05380 wait_for_hangup(chan, "10");
05381 else
05382 wait_for_hangup(chan, data);
05383 return -1;
05384 }
05385
05386
05387
05388
05389 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
05390 {
05391 ast_indicate(chan, AST_CONTROL_CONGESTION);
05392
05393
05394 if (chan->_state != AST_STATE_UP)
05395 ast_setstate(chan, AST_STATE_BUSY);
05396 if( ast_strlen_zero(data) )
05397 wait_for_hangup(chan, "10");
05398 else
05399 wait_for_hangup(chan, data);
05400 return -1;
05401 }
05402
05403
05404
05405
05406 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05407 {
05408 int delay = 0;
05409 int res;
05410
05411 if (chan->_state == AST_STATE_UP)
05412 delay = 0;
05413 else if (!ast_strlen_zero(data))
05414 delay = atoi(data);
05415
05416 res = ast_answer(chan);
05417 if (res)
05418 return res;
05419
05420 if (delay)
05421 res = ast_safe_sleep(chan, delay);
05422
05423 return res;
05424 }
05425
05426 AST_APP_OPTIONS(resetcdr_opts, {
05427 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05428 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05429 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05430 });
05431
05432
05433
05434
05435 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05436 {
05437 char *args;
05438 struct ast_flags flags = { 0 };
05439
05440 if (!ast_strlen_zero(data)) {
05441 args = ast_strdupa(data);
05442 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05443 }
05444
05445 ast_cdr_reset(chan->cdr, &flags);
05446
05447 return 0;
05448 }
05449
05450
05451
05452
05453 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05454 {
05455
05456 ast_cdr_setamaflags(chan, data ? data : "");
05457 return 0;
05458 }
05459
05460
05461
05462
05463 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05464 {
05465 if (!ast_strlen_zero(data)) {
05466 int cause;
05467 char *endptr;
05468
05469 if ((cause = ast_str2cause(data)) > -1) {
05470 chan->hangupcause = cause;
05471 return -1;
05472 }
05473
05474 cause = strtol((const char *) data, &endptr, 10);
05475 if (cause != 0 || (data != endptr)) {
05476 chan->hangupcause = cause;
05477 return -1;
05478 }
05479
05480 ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
05481 }
05482
05483 if (!chan->hangupcause) {
05484 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05485 }
05486
05487 return -1;
05488 }
05489
05490
05491
05492
05493 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05494 {
05495 int res=0;
05496 char *s, *ts;
05497 struct ast_timing timing;
05498
05499 if (ast_strlen_zero(data)) {
05500 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05501 return -1;
05502 }
05503
05504 ts = s = ast_strdupa(data);
05505
05506
05507 strsep(&ts,"?");
05508
05509
05510 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05511 res = pbx_builtin_goto(chan, ts);
05512
05513 return res;
05514 }
05515
05516
05517
05518
05519 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05520 {
05521 char *s, *appname;
05522 struct ast_timing timing;
05523 struct ast_app *app;
05524 static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05525
05526 if (ast_strlen_zero(data)) {
05527 ast_log(LOG_WARNING, "%s\n", usage);
05528 return -1;
05529 }
05530
05531 appname = ast_strdupa(data);
05532
05533 s = strsep(&appname,"?");
05534 if (!appname) {
05535 ast_log(LOG_WARNING, "%s\n", usage);
05536 return -1;
05537 }
05538
05539 if (!ast_build_timing(&timing, s)) {
05540 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
05541 return -1;
05542 }
05543
05544 if (!ast_check_timing(&timing))
05545 return 0;
05546
05547
05548 if ((s = strchr(appname, '|')))
05549 *s++ = '\0';
05550
05551 if ((app = pbx_findapp(appname))) {
05552 return pbx_exec(chan, app, S_OR(s, ""));
05553 } else {
05554 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
05555 return -1;
05556 }
05557 }
05558
05559
05560
05561
05562 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05563 {
05564 double s;
05565 int ms;
05566
05567
05568 if (data && (s = atof(data)) > 0) {
05569 ms = s * 1000.0;
05570 return ast_safe_sleep(chan, ms);
05571 }
05572 return 0;
05573 }
05574
05575
05576
05577
05578 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05579 {
05580 int ms, res;
05581 double sec;
05582 struct ast_flags flags = {0};
05583 char *opts[1] = { NULL };
05584 char *parse;
05585 AST_DECLARE_APP_ARGS(args,
05586 AST_APP_ARG(timeout);
05587 AST_APP_ARG(options);
05588 );
05589
05590 if (!ast_strlen_zero(data)) {
05591 parse = ast_strdupa(data);
05592 AST_STANDARD_APP_ARGS(args, parse);
05593 } else
05594 memset(&args, 0, sizeof(args));
05595
05596 if (args.options)
05597 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
05598
05599 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
05600 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
05601 } else if (ast_test_flag(&flags, WAITEXTEN_MOH))
05602 ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
05603
05604
05605 if (args.timeout && (sec = atof(args.timeout)) > 0.0)
05606 ms = 1000 * sec;
05607 else if (chan->pbx)
05608 ms = chan->pbx->rtimeout * 1000;
05609 else
05610 ms = 10000;
05611 res = ast_waitfordigit(chan, ms);
05612 if (!res) {
05613 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05614 if (option_verbose > 2)
05615 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05616 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05617 if (option_verbose > 2)
05618 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05619 set_ext_pri(chan, "t", 0);
05620 } else {
05621 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05622 res = -1;
05623 }
05624 }
05625
05626 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05627 ast_indicate(chan, AST_CONTROL_UNHOLD);
05628
05629 return res;
05630 }
05631
05632
05633
05634
05635 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05636 {
05637 int res = 0;
05638 struct ast_flags flags = {0};
05639 char *parse;
05640 AST_DECLARE_APP_ARGS(args,
05641 AST_APP_ARG(filename);
05642 AST_APP_ARG(options);
05643 AST_APP_ARG(lang);
05644 AST_APP_ARG(context);
05645 );
05646
05647 if (ast_strlen_zero(data)) {
05648 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05649 return -1;
05650 }
05651
05652 parse = ast_strdupa(data);
05653
05654 AST_STANDARD_APP_ARGS(args, parse);
05655
05656 if (ast_strlen_zero(args.lang))
05657 args.lang = (char *)chan->language;
05658
05659 if (ast_strlen_zero(args.context))
05660 args.context = chan->context;
05661
05662 if (args.options) {
05663 if (!strcasecmp(args.options, "skip"))
05664 flags.flags = BACKGROUND_SKIP;
05665 else if (!strcasecmp(args.options, "noanswer"))
05666 flags.flags = BACKGROUND_NOANSWER;
05667 else
05668 ast_app_parse_options(background_opts, &flags, NULL, args.options);
05669 }
05670
05671
05672 if (chan->_state != AST_STATE_UP) {
05673 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05674 return 0;
05675 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05676 res = ast_answer(chan);
05677 }
05678 }
05679
05680 if (!res) {
05681 char *back = args.filename;
05682 char *front;
05683 ast_stopstream(chan);
05684
05685 while (!res && (front = strsep(&back, "&")) ) {
05686 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
05687 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05688 res = 0;
05689 break;
05690 }
05691 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05692 res = ast_waitstream(chan, "");
05693 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05694 res = ast_waitstream_exten(chan, args.context);
05695 } else {
05696 res = ast_waitstream(chan, AST_DIGIT_ANY);
05697 }
05698 ast_stopstream(chan);
05699 }
05700 }
05701 if (args.context != chan->context && res) {
05702 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05703 ast_copy_string(chan->context, args.context, sizeof(chan->context));
05704 chan->priority = 0;
05705 res = 0;
05706 }
05707 return res;
05708 }
05709
05710
05711
05712
05713 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05714 {
05715 int res = ast_parseable_goto(chan, data);
05716 if (!res && (option_verbose > 2))
05717 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05718 return res;
05719 }
05720
05721
05722 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05723 {
05724 struct ast_var_t *variables;
05725 const char *var, *val;
05726 int total = 0;
05727
05728 if (!chan)
05729 return 0;
05730
05731 memset(buf, 0, size);
05732
05733 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05734 if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
05735
05736 ) {
05737 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05738 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05739 break;
05740 } else
05741 total++;
05742 } else
05743 break;
05744 }
05745
05746 return total;
05747 }
05748
05749 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05750 {
05751 struct ast_var_t *variables;
05752 const char *ret = NULL;
05753 int i;
05754 struct varshead *places[2] = { NULL, &globals };
05755
05756 if (!name)
05757 return NULL;
05758 if (chan)
05759 places[0] = &chan->varshead;
05760
05761 for (i = 0; i < 2; i++) {
05762 if (!places[i])
05763 continue;
05764 if (places[i] == &globals)
05765 ast_mutex_lock(&globalslock);
05766 AST_LIST_TRAVERSE(places[i], variables, entries) {
05767 if (!strcmp(name, ast_var_name(variables))) {
05768 ret = ast_var_value(variables);
05769 break;
05770 }
05771 }
05772 if (places[i] == &globals)
05773 ast_mutex_unlock(&globalslock);
05774 if (ret)
05775 break;
05776 }
05777
05778 return ret;
05779 }
05780
05781 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05782 {
05783 struct ast_var_t *newvariable;
05784 struct varshead *headp;
05785
05786 if (name[strlen(name)-1] == ')') {
05787 char *function = ast_strdupa(name);
05788
05789 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05790 ast_func_write(chan, function, value);
05791 return;
05792 }
05793
05794 headp = (chan) ? &chan->varshead : &globals;
05795
05796 if (value) {
05797 if ((option_verbose > 1) && (headp == &globals))
05798 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05799 newvariable = ast_var_assign(name, value);
05800 if (headp == &globals)
05801 ast_mutex_lock(&globalslock);
05802 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05803 if (headp == &globals)
05804 ast_mutex_unlock(&globalslock);
05805 }
05806 }
05807
05808 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
05809 {
05810 struct ast_var_t *newvariable;
05811 struct varshead *headp;
05812 const char *nametail = name;
05813
05814
05815 if (name[strlen(name)-1] == ')') {
05816 char *function = ast_strdupa(name);
05817
05818 ast_func_write(chan, function, value);
05819 return;
05820 }
05821
05822 headp = (chan) ? &chan->varshead : &globals;
05823
05824
05825 if (*nametail == '_') {
05826 nametail++;
05827 if (*nametail == '_')
05828 nametail++;
05829 }
05830
05831 if (headp == &globals)
05832 ast_mutex_lock(&globalslock);
05833 AST_LIST_TRAVERSE (headp, newvariable, entries) {
05834 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
05835
05836 AST_LIST_REMOVE(headp, newvariable, entries);
05837 ast_var_delete(newvariable);
05838 break;
05839 }
05840 }
05841
05842 if (value) {
05843 if ((option_verbose > 1) && (headp == &globals))
05844 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05845 newvariable = ast_var_assign(name, value);
05846 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05847 }
05848
05849 if (headp == &globals)
05850 ast_mutex_unlock(&globalslock);
05851 }
05852
05853 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
05854 {
05855 char *name, *value, *mydata;
05856 int argc;
05857 char *argv[24];
05858 int global = 0;
05859 int x;
05860
05861 if (ast_strlen_zero(data)) {
05862 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
05863 return 0;
05864 }
05865
05866 mydata = ast_strdupa(data);
05867 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
05868
05869
05870 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
05871 argc--;
05872 if (strchr(argv[argc], 'g'))
05873 global = 1;
05874 }
05875
05876 for (x = 0; x < argc; x++) {
05877 name = argv[x];
05878 if ((value = strchr(name, '='))) {
05879 *value++ = '\0';
05880 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
05881 } else
05882 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
05883 }
05884
05885 return(0);
05886 }
05887
05888 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
05889 {
05890 char *name;
05891 char *value;
05892 char *channel;
05893 char tmp[VAR_BUF_SIZE]="";
05894
05895 if (ast_strlen_zero(data)) {
05896 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
05897 return 0;
05898 }
05899
05900 value = ast_strdupa(data);
05901 name = strsep(&value,"=");
05902 channel = strsep(&value,"|");
05903 if (channel && value && name) {
05904 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
05905 if (chan2) {
05906 char *s = alloca(strlen(value) + 4);
05907 if (s) {
05908 sprintf(s, "${%s}", value);
05909 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
05910 }
05911 ast_channel_unlock(chan2);
05912 }
05913 pbx_builtin_setvar_helper(chan, name, tmp);
05914 }
05915
05916 return(0);
05917 }
05918
05919
05920 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
05921 {
05922 char *name;
05923 char *stringp = data;
05924 static int dep_warning = 0;
05925
05926 if (ast_strlen_zero(data)) {
05927 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
05928 return 0;
05929 }
05930
05931 name = strsep(&stringp, "=");
05932
05933 if (!dep_warning) {
05934 dep_warning = 1;
05935 ast_log(LOG_WARNING, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
05936 }
05937
05938
05939 pbx_builtin_setvar_helper(NULL, name, stringp);
05940
05941 return(0);
05942 }
05943
05944 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
05945 {
05946 return 0;
05947 }
05948
05949 void pbx_builtin_clear_globals(void)
05950 {
05951 struct ast_var_t *vardata;
05952
05953 ast_mutex_lock(&globalslock);
05954 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
05955 ast_var_delete(vardata);
05956 ast_mutex_unlock(&globalslock);
05957 }
05958
05959 int pbx_checkcondition(const char *condition)
05960 {
05961 if (ast_strlen_zero(condition))
05962 return 0;
05963 else if (*condition >= '0' && *condition <= '9')
05964 return atoi(condition);
05965 else
05966 return 1;
05967 }
05968
05969 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
05970 {
05971 char *condition, *branch1, *branch2, *branch;
05972 int rc;
05973 char *stringp;
05974
05975 if (ast_strlen_zero(data)) {
05976 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
05977 return 0;
05978 }
05979
05980 stringp = ast_strdupa(data);
05981 condition = strsep(&stringp,"?");
05982 branch1 = strsep(&stringp,":");
05983 branch2 = strsep(&stringp,"");
05984 branch = pbx_checkcondition(condition) ? branch1 : branch2;
05985
05986 if (ast_strlen_zero(branch)) {
05987 if (option_debug)
05988 ast_log(LOG_DEBUG, "Not taking any branch\n");
05989 return 0;
05990 }
05991
05992 rc = pbx_builtin_goto(chan, branch);
05993
05994 return rc;
05995 }
05996
05997 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
05998 {
05999 char tmp[256];
06000 char *number = tmp;
06001 char *options;
06002
06003 if (ast_strlen_zero(data)) {
06004 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06005 return -1;
06006 }
06007 ast_copy_string(tmp, data, sizeof(tmp));
06008 strsep(&number, "|");
06009 options = strsep(&number, "|");
06010 if (options) {
06011 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06012 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06013 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06014 return -1;
06015 }
06016 }
06017 return ast_say_number(chan, atoi(tmp), "", chan->language, options);
06018 }
06019
06020 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06021 {
06022 int res = 0;
06023
06024 if (data)
06025 res = ast_say_digit_str(chan, data, "", chan->language);
06026 return res;
06027 }
06028
06029 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06030 {
06031 int res = 0;
06032
06033 if (data)
06034 res = ast_say_character_str(chan, data, "", chan->language);
06035 return res;
06036 }
06037
06038 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06039 {
06040 int res = 0;
06041
06042 if (data)
06043 res = ast_say_phonetic_str(chan, data, "", chan->language);
06044 return res;
06045 }
06046
06047 int load_pbx(void)
06048 {
06049 int x;
06050
06051
06052 if (option_verbose) {
06053 ast_verbose( "Asterisk PBX Core Initializing\n");
06054 ast_verbose( "Registering builtin applications:\n");
06055 }
06056 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
06057
06058
06059 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06060 if (option_verbose)
06061 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06062 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06063 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06064 return -1;
06065 }
06066 }
06067 return 0;
06068 }
06069
06070
06071
06072
06073 int ast_lock_contexts()
06074 {
06075 return ast_mutex_lock(&conlock);
06076 }
06077
06078 int ast_unlock_contexts()
06079 {
06080 return ast_mutex_unlock(&conlock);
06081 }
06082
06083
06084
06085
06086 int ast_lock_context(struct ast_context *con)
06087 {
06088 return ast_mutex_lock(&con->lock);
06089 }
06090
06091 int ast_unlock_context(struct ast_context *con)
06092 {
06093 return ast_mutex_unlock(&con->lock);
06094 }
06095
06096
06097
06098
06099 const char *ast_get_context_name(struct ast_context *con)
06100 {
06101 return con ? con->name : NULL;
06102 }
06103
06104 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
06105 {
06106 return exten ? exten->parent : NULL;
06107 }
06108
06109 const char *ast_get_extension_name(struct ast_exten *exten)
06110 {
06111 return exten ? exten->exten : NULL;
06112 }
06113
06114 const char *ast_get_extension_label(struct ast_exten *exten)
06115 {
06116 return exten ? exten->label : NULL;
06117 }
06118
06119 const char *ast_get_include_name(struct ast_include *inc)
06120 {
06121 return inc ? inc->name : NULL;
06122 }
06123
06124 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06125 {
06126 return ip ? ip->pattern : NULL;
06127 }
06128
06129 int ast_get_extension_priority(struct ast_exten *exten)
06130 {
06131 return exten ? exten->priority : -1;
06132 }
06133
06134
06135
06136
06137 const char *ast_get_context_registrar(struct ast_context *c)
06138 {
06139 return c ? c->registrar : NULL;
06140 }
06141
06142 const char *ast_get_extension_registrar(struct ast_exten *e)
06143 {
06144 return e ? e->registrar : NULL;
06145 }
06146
06147 const char *ast_get_include_registrar(struct ast_include *i)
06148 {
06149 return i ? i->registrar : NULL;
06150 }
06151
06152 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06153 {
06154 return ip ? ip->registrar : NULL;
06155 }
06156
06157 int ast_get_extension_matchcid(struct ast_exten *e)
06158 {
06159 return e ? e->matchcid : 0;
06160 }
06161
06162 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06163 {
06164 return e ? e->cidmatch : NULL;
06165 }
06166
06167 const char *ast_get_extension_app(struct ast_exten *e)
06168 {
06169 return e ? e->app : NULL;
06170 }
06171
06172 void *ast_get_extension_app_data(struct ast_exten *e)
06173 {
06174 return e ? e->data : NULL;
06175 }
06176
06177 const char *ast_get_switch_name(struct ast_sw *sw)
06178 {
06179 return sw ? sw->name : NULL;
06180 }
06181
06182 const char *ast_get_switch_data(struct ast_sw *sw)
06183 {
06184 return sw ? sw->data : NULL;
06185 }
06186
06187 const char *ast_get_switch_registrar(struct ast_sw *sw)
06188 {
06189 return sw ? sw->registrar : NULL;
06190 }
06191
06192
06193
06194
06195 struct ast_context *ast_walk_contexts(struct ast_context *con)
06196 {
06197 return con ? con->next : contexts;
06198 }
06199
06200 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06201 struct ast_exten *exten)
06202 {
06203 if (!exten)
06204 return con ? con->root : NULL;
06205 else
06206 return exten->next;
06207 }
06208
06209 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06210 struct ast_sw *sw)
06211 {
06212 if (!sw)
06213 return con ? AST_LIST_FIRST(&con->alts) : NULL;
06214 else
06215 return AST_LIST_NEXT(sw, list);
06216 }
06217
06218 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06219 struct ast_exten *priority)
06220 {
06221 return priority ? priority->peer : exten;
06222 }
06223
06224 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06225 struct ast_include *inc)
06226 {
06227 if (!inc)
06228 return con ? con->includes : NULL;
06229 else
06230 return inc->next;
06231 }
06232
06233 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06234 struct ast_ignorepat *ip)
06235 {
06236 if (!ip)
06237 return con ? con->ignorepats : NULL;
06238 else
06239 return ip->next;
06240 }
06241
06242 int ast_context_verify_includes(struct ast_context *con)
06243 {
06244 struct ast_include *inc = NULL;
06245 int res = 0;
06246
06247 while ( (inc = ast_walk_context_includes(con, inc)) )
06248 if (!ast_context_find(inc->rname)) {
06249 res = -1;
06250 ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
06251 ast_get_context_name(con), inc->rname);
06252 }
06253 return res;
06254 }
06255
06256
06257 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
06258 {
06259 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06260
06261 if (!chan)
06262 return -2;
06263
06264 if (context == NULL)
06265 context = chan->context;
06266 if (exten == NULL)
06267 exten = chan->exten;
06268
06269 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06270 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
06271 return goto_func(chan, context, exten, priority);
06272 else
06273 return -3;
06274 }
06275
06276 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
06277 {
06278 return __ast_goto_if_exists(chan, context, exten, priority, 0);
06279 }
06280
06281 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
06282 {
06283 return __ast_goto_if_exists(chan, context, exten, priority, 1);
06284 }
06285
06286 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06287 {
06288 char *exten, *pri, *context;
06289 char *stringp;
06290 int ipri;
06291 int mode = 0;
06292
06293 if (ast_strlen_zero(goto_string)) {
06294 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06295 return -1;
06296 }
06297 stringp = ast_strdupa(goto_string);
06298 context = strsep(&stringp, "|");
06299 exten = strsep(&stringp, "|");
06300 pri = strsep(&stringp, "|");
06301 if (!exten) {
06302 pri = context;
06303 exten = NULL;
06304 context = NULL;
06305 } else if (!pri) {
06306 pri = exten;
06307 exten = context;
06308 context = NULL;
06309 }
06310 if (*pri == '+') {
06311 mode = 1;
06312 pri++;
06313 } else if (*pri == '-') {
06314 mode = -1;
06315 pri++;
06316 }
06317 if (sscanf(pri, "%d", &ipri) != 1) {
06318 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
06319 pri, chan->cid.cid_num)) < 1) {
06320 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06321 return -1;
06322 } else
06323 mode = 0;
06324 }
06325
06326
06327 if (mode)
06328 ipri = chan->priority + (ipri * mode);
06329
06330 ast_explicit_goto(chan, context, exten, ipri);
06331 ast_cdr_update(chan);
06332 return 0;
06333
06334 }