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