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