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