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