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