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