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