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: 120282 $")
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 if (c->amaflags) {
02400 if (!c->cdr) {
02401 c->cdr = ast_cdr_alloc();
02402 if (!c->cdr) {
02403 ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
02404 free(c->pbx);
02405 return -1;
02406 }
02407 ast_cdr_init(c->cdr, c);
02408 }
02409 }
02410
02411 c->pbx->rtimeout = 10;
02412 c->pbx->dtimeout = 5;
02413
02414 autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
02415 ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
02416
02417
02418 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02419
02420 if (option_verbose > 1)
02421 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);
02422
02423
02424
02425
02426 set_ext_pri(c, "s", 1);
02427 if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02428
02429 if (option_verbose > 1)
02430 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);
02431 ast_copy_string(c->context, "default", sizeof(c->context));
02432 }
02433 }
02434 if (c->cdr && ast_tvzero(c->cdr->start))
02435 ast_cdr_start(c->cdr);
02436 for (;;) {
02437 char dst_exten[256];
02438 int pos = 0;
02439 int digit = 0;
02440
02441
02442 while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02443 found = 1;
02444 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02445
02446 if (strchr("0123456789ABCDEF*#", res)) {
02447 if (option_debug)
02448 ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
02449 pos = 0;
02450 dst_exten[pos++] = digit = res;
02451 dst_exten[pos] = '\0';
02452 break;
02453 }
02454 if (res == AST_PBX_KEEPALIVE) {
02455 if (option_debug)
02456 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02457 if (option_verbose > 1)
02458 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02459 error = 1;
02460 break;
02461 }
02462 if (option_debug)
02463 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02464 if (option_verbose > 1)
02465 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02466 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02467 c->_softhangup = 0;
02468 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02469
02470 } else {
02471 if (c->cdr)
02472 ast_cdr_update(c);
02473 error = 1;
02474 break;
02475 }
02476 }
02477 if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02478 c->_softhangup = 0;
02479 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
02480 set_ext_pri(c, "T", 0);
02481
02482 c->whentohangup = 0;
02483 c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
02484 } else if (c->_softhangup) {
02485 if (option_debug)
02486 ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
02487 c->exten, c->priority);
02488 error = 1;
02489 break;
02490 }
02491 c->priority++;
02492 }
02493 if (error)
02494 break;
02495
02496
02497
02498 if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
02499
02500
02501
02502 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02503 if (option_verbose > 2)
02504 ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
02505 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
02506 set_ext_pri(c, "i", 1);
02507 } else {
02508 ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
02509 c->name, c->exten, c->context);
02510 error = 1;
02511 break;
02512 }
02513 } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02514
02515 c->_softhangup = 0;
02516 } else {
02517 int waittime = 0;
02518 if (digit)
02519 waittime = c->pbx->dtimeout;
02520 else if (!autofallthrough)
02521 waittime = c->pbx->rtimeout;
02522 if (!waittime) {
02523 const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
02524 if (!status)
02525 status = "UNKNOWN";
02526 if (option_verbose > 2)
02527 ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
02528 if (!strcasecmp(status, "CONGESTION"))
02529 res = pbx_builtin_congestion(c, "10");
02530 else if (!strcasecmp(status, "CHANUNAVAIL"))
02531 res = pbx_builtin_congestion(c, "10");
02532 else if (!strcasecmp(status, "BUSY"))
02533 res = pbx_builtin_busy(c, "10");
02534 error = 1;
02535 break;
02536 }
02537
02538 if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
02539 break;
02540 if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num))
02541 set_ext_pri(c, dst_exten, 1);
02542 else {
02543
02544 if (!ast_strlen_zero(dst_exten)) {
02545
02546 if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02547 if (option_verbose > 2)
02548 ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
02549 pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
02550 set_ext_pri(c, "i", 1);
02551 } else {
02552 ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
02553 found = 1;
02554 break;
02555 }
02556 } else {
02557
02558 if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
02559 if (option_verbose > 2)
02560 ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
02561 set_ext_pri(c, "t", 1);
02562 } else {
02563 ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
02564 found = 1;
02565 break;
02566 }
02567 }
02568 }
02569 if (c->cdr) {
02570 if (option_verbose > 2)
02571 ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
02572 ast_cdr_update(c);
02573 }
02574 }
02575 }
02576 if (!found && !error)
02577 ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
02578 if (res != AST_PBX_KEEPALIVE)
02579 ast_softhangup(c, c->hangupcause ? c->hangupcause : AST_CAUSE_NORMAL_CLEARING);
02580 if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
02581 if (c->cdr && ast_opt_end_cdr_before_h_exten)
02582 ast_cdr_end(c->cdr);
02583 set_ext_pri(c, "h", 1);
02584 while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02585 if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02586
02587 if (option_debug)
02588 ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02589 if (option_verbose > 1)
02590 ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02591 break;
02592 }
02593 c->priority++;
02594 }
02595 }
02596 ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02597
02598 pbx_destroy(c->pbx);
02599 c->pbx = NULL;
02600 if (res != AST_PBX_KEEPALIVE)
02601 ast_hangup(c);
02602 return 0;
02603 }
02604
02605
02606 static int increase_call_count(const struct ast_channel *c)
02607 {
02608 int failed = 0;
02609 double curloadavg;
02610 ast_mutex_lock(&maxcalllock);
02611 if (option_maxcalls) {
02612 if (countcalls >= option_maxcalls) {
02613 ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
02614 failed = -1;
02615 }
02616 }
02617 if (option_maxload) {
02618 getloadavg(&curloadavg, 1);
02619 if (curloadavg >= option_maxload) {
02620 ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
02621 failed = -1;
02622 }
02623 }
02624 if (!failed)
02625 countcalls++;
02626 ast_mutex_unlock(&maxcalllock);
02627
02628 return failed;
02629 }
02630
02631 static void decrease_call_count(void)
02632 {
02633 ast_mutex_lock(&maxcalllock);
02634 if (countcalls > 0)
02635 countcalls--;
02636 ast_mutex_unlock(&maxcalllock);
02637 }
02638
02639 static void destroy_exten(struct ast_exten *e)
02640 {
02641 if (e->priority == PRIORITY_HINT)
02642 ast_remove_hint(e);
02643
02644 if (e->datad)
02645 e->datad(e->data);
02646 free(e);
02647 }
02648
02649 static void *pbx_thread(void *data)
02650 {
02651
02652
02653
02654
02655
02656
02657
02658
02659 struct ast_channel *c = data;
02660
02661 __ast_pbx_run(c);
02662 decrease_call_count();
02663
02664 pthread_exit(NULL);
02665
02666 return NULL;
02667 }
02668
02669 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
02670 {
02671 pthread_t t;
02672 pthread_attr_t attr;
02673
02674 if (!c) {
02675 ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
02676 return AST_PBX_FAILED;
02677 }
02678
02679 if (increase_call_count(c))
02680 return AST_PBX_CALL_LIMIT;
02681
02682
02683 pthread_attr_init(&attr);
02684 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02685 if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
02686 ast_log(LOG_WARNING, "Failed to create new channel thread\n");
02687 pthread_attr_destroy(&attr);
02688 return AST_PBX_FAILED;
02689 }
02690 pthread_attr_destroy(&attr);
02691
02692 return AST_PBX_SUCCESS;
02693 }
02694
02695 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
02696 {
02697 enum ast_pbx_result res = AST_PBX_SUCCESS;
02698
02699 if (increase_call_count(c))
02700 return AST_PBX_CALL_LIMIT;
02701
02702 res = __ast_pbx_run(c);
02703 decrease_call_count();
02704
02705 return res;
02706 }
02707
02708 int ast_active_calls(void)
02709 {
02710 return countcalls;
02711 }
02712
02713 int pbx_set_autofallthrough(int newval)
02714 {
02715 int oldval = autofallthrough;
02716 autofallthrough = newval;
02717 return oldval;
02718 }
02719
02720
02721
02722
02723 static struct ast_context *find_context_locked(const char *context)
02724 {
02725 struct ast_context *c = NULL;
02726
02727 ast_rdlock_contexts();
02728 while ( (c = ast_walk_contexts(c)) ) {
02729 if (!strcmp(ast_get_context_name(c), context))
02730 return c;
02731 }
02732 ast_unlock_contexts();
02733
02734 return NULL;
02735 }
02736
02737
02738
02739
02740
02741
02742 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
02743 {
02744 int ret = -1;
02745 struct ast_context *c = find_context_locked(context);
02746
02747 if (c) {
02748
02749 ret = ast_context_remove_include2(c, include, registrar);
02750 ast_unlock_contexts();
02751 }
02752 return ret;
02753 }
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
02764 {
02765 struct ast_include *i, *pi = NULL;
02766 int ret = -1;
02767
02768 ast_mutex_lock(&con->lock);
02769
02770
02771 for (i = con->includes; i; pi = i, i = i->next) {
02772 if (!strcmp(i->name, include) &&
02773 (!registrar || !strcmp(i->registrar, registrar))) {
02774
02775 if (pi)
02776 pi->next = i->next;
02777 else
02778 con->includes = i->next;
02779
02780 free(i);
02781 ret = 0;
02782 break;
02783 }
02784 }
02785
02786 ast_mutex_unlock(&con->lock);
02787 return ret;
02788 }
02789
02790
02791
02792
02793
02794
02795 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
02796 {
02797 int ret = -1;
02798 struct ast_context *c = find_context_locked(context);
02799
02800 if (c) {
02801
02802 ret = ast_context_remove_switch2(c, sw, data, registrar);
02803 ast_unlock_contexts();
02804 }
02805 return ret;
02806 }
02807
02808
02809
02810
02811
02812
02813
02814
02815
02816 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
02817 {
02818 struct ast_sw *i;
02819 int ret = -1;
02820
02821 ast_mutex_lock(&con->lock);
02822
02823
02824 AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
02825 if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
02826 (!registrar || !strcmp(i->registrar, registrar))) {
02827
02828 AST_LIST_REMOVE_CURRENT(&con->alts, list);
02829 free(i);
02830 ret = 0;
02831 break;
02832 }
02833 }
02834 AST_LIST_TRAVERSE_SAFE_END
02835
02836 ast_mutex_unlock(&con->lock);
02837
02838 return ret;
02839 }
02840
02841
02842
02843
02844
02845
02846 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
02847 {
02848 int ret = -1;
02849 struct ast_context *c = find_context_locked(context);
02850
02851 if (c) {
02852 ret = ast_context_remove_extension2(c, extension, priority, registrar);
02853 ast_unlock_contexts();
02854 }
02855 return ret;
02856 }
02857
02858
02859
02860
02861
02862
02863
02864
02865
02866
02867
02868 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
02869 {
02870 struct ast_exten *exten, *prev_exten = NULL;
02871 struct ast_exten *peer;
02872
02873 ast_mutex_lock(&con->lock);
02874
02875
02876 for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
02877 if (!strcmp(exten->exten, extension) &&
02878 (!registrar || !strcmp(exten->registrar, registrar)))
02879 break;
02880 }
02881 if (!exten) {
02882
02883 ast_mutex_unlock(&con->lock);
02884 return -1;
02885 }
02886
02887
02888 if (priority == 0) {
02889
02890 if (prev_exten)
02891 prev_exten->next = exten->next;
02892 else
02893 con->root = exten->next;
02894
02895
02896 while ( (peer = exten) ) {
02897 exten = peer->peer;
02898 destroy_exten(peer);
02899 }
02900 } else {
02901
02902 struct ast_exten *previous_peer = NULL;
02903
02904 for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
02905 if (peer->priority == priority &&
02906 (!registrar || !strcmp(peer->registrar, registrar) ))
02907 break;
02908 }
02909 if (!peer) {
02910 ast_mutex_unlock(&con->lock);
02911 return -1;
02912 }
02913
02914 if (!previous_peer) {
02915
02916
02917
02918
02919 struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
02920
02921 if (!prev_exten)
02922 con->root = next_node;
02923 else
02924 prev_exten->next = next_node;
02925 if (peer->peer)
02926 peer->peer->next = peer->next;
02927 } else {
02928 previous_peer->peer = peer->peer;
02929 }
02930
02931
02932 destroy_exten(peer);
02933
02934 }
02935 ast_mutex_unlock(&con->lock);
02936 return 0;
02937 }
02938
02939
02940
02941
02942
02943
02944
02945 int ast_context_lockmacro(const char *context)
02946 {
02947 struct ast_context *c = NULL;
02948 int ret = -1;
02949
02950 ast_rdlock_contexts();
02951
02952 while ((c = ast_walk_contexts(c))) {
02953 if (!strcmp(ast_get_context_name(c), context)) {
02954 ret = 0;
02955 break;
02956 }
02957 }
02958
02959 ast_unlock_contexts();
02960
02961
02962 if (ret == 0)
02963 ret = ast_mutex_lock(&c->macrolock);
02964
02965 return ret;
02966 }
02967
02968
02969
02970
02971
02972
02973 int ast_context_unlockmacro(const char *context)
02974 {
02975 struct ast_context *c = NULL;
02976 int ret = -1;
02977
02978 ast_rdlock_contexts();
02979
02980 while ((c = ast_walk_contexts(c))) {
02981 if (!strcmp(ast_get_context_name(c), context)) {
02982 ret = 0;
02983 break;
02984 }
02985 }
02986
02987 ast_unlock_contexts();
02988
02989
02990 if (ret == 0)
02991 ret = ast_mutex_unlock(&c->macrolock);
02992
02993 return ret;
02994 }
02995
02996
02997 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
02998 {
02999 struct ast_app *tmp, *cur = NULL;
03000 char tmps[80];
03001 int length;
03002
03003 AST_LIST_LOCK(&apps);
03004 AST_LIST_TRAVERSE(&apps, tmp, list) {
03005 if (!strcasecmp(app, tmp->name)) {
03006 ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
03007 AST_LIST_UNLOCK(&apps);
03008 return -1;
03009 }
03010 }
03011
03012 length = sizeof(*tmp) + strlen(app) + 1;
03013
03014 if (!(tmp = ast_calloc(1, length))) {
03015 AST_LIST_UNLOCK(&apps);
03016 return -1;
03017 }
03018
03019 strcpy(tmp->name, app);
03020 tmp->execute = execute;
03021 tmp->synopsis = synopsis;
03022 tmp->description = description;
03023
03024
03025 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
03026 if (strcasecmp(tmp->name, cur->name) < 0) {
03027 AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
03028 break;
03029 }
03030 }
03031 AST_LIST_TRAVERSE_SAFE_END
03032 if (!cur)
03033 AST_LIST_INSERT_TAIL(&apps, tmp, list);
03034
03035 if (option_verbose > 1)
03036 ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
03037
03038 AST_LIST_UNLOCK(&apps);
03039
03040 return 0;
03041 }
03042
03043
03044
03045
03046
03047 int ast_register_switch(struct ast_switch *sw)
03048 {
03049 struct ast_switch *tmp;
03050
03051 AST_LIST_LOCK(&switches);
03052 AST_LIST_TRAVERSE(&switches, tmp, list) {
03053 if (!strcasecmp(tmp->name, sw->name)) {
03054 AST_LIST_UNLOCK(&switches);
03055 ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
03056 return -1;
03057 }
03058 }
03059 AST_LIST_INSERT_TAIL(&switches, sw, list);
03060 AST_LIST_UNLOCK(&switches);
03061
03062 return 0;
03063 }
03064
03065 void ast_unregister_switch(struct ast_switch *sw)
03066 {
03067 AST_LIST_LOCK(&switches);
03068 AST_LIST_REMOVE(&switches, sw, list);
03069 AST_LIST_UNLOCK(&switches);
03070 }
03071
03072
03073
03074
03075 static char show_applications_help[] =
03076 "Usage: core show applications [{like|describing} <text>]\n"
03077 " List applications which are currently available.\n"
03078 " If 'like', <text> will be a substring of the app name\n"
03079 " If 'describing', <text> will be a substring of the description\n";
03080
03081 static char show_functions_help[] =
03082 "Usage: core show functions [like <text>]\n"
03083 " List builtin functions, optionally only those matching a given string\n";
03084
03085 static char show_switches_help[] =
03086 "Usage: core show switches\n"
03087 " List registered switches\n";
03088
03089 static char show_hints_help[] =
03090 "Usage: core show hints\n"
03091 " List registered hints\n";
03092
03093 static char show_globals_help[] =
03094 "Usage: core show globals\n"
03095 " List current global dialplan variables and their values\n";
03096
03097 static char show_application_help[] =
03098 "Usage: core show application <application> [<application> [<application> [...]]]\n"
03099 " Describes a particular application.\n";
03100
03101 static char show_function_help[] =
03102 "Usage: core show function <function>\n"
03103 " Describe a particular dialplan function.\n";
03104
03105 static char show_dialplan_help[] =
03106 "Usage: dialplan show [exten@][context]\n"
03107 " Show dialplan\n";
03108
03109 static char set_global_help[] =
03110 "Usage: core set global <name> <value>\n"
03111 " Set global dialplan variable <name> to <value>\n";
03112
03113
03114
03115
03116
03117
03118
03119
03120
03121
03122
03123 static char *complete_show_application(const char *line, const char *word, int pos, int state)
03124 {
03125 struct ast_app *a;
03126 char *ret = NULL;
03127 int which = 0;
03128 int wordlen = strlen(word);
03129
03130
03131 AST_LIST_LOCK(&apps);
03132 AST_LIST_TRAVERSE(&apps, a, list) {
03133 if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
03134 ret = strdup(a->name);
03135 break;
03136 }
03137 }
03138 AST_LIST_UNLOCK(&apps);
03139
03140 return ret;
03141 }
03142
03143 static int handle_show_application_deprecated(int fd, int argc, char *argv[])
03144 {
03145 struct ast_app *a;
03146 int app, no_registered_app = 1;
03147
03148 if (argc < 3)
03149 return RESULT_SHOWUSAGE;
03150
03151
03152 AST_LIST_LOCK(&apps);
03153 AST_LIST_TRAVERSE(&apps, a, list) {
03154
03155
03156 for (app = 2; app < argc; app++) {
03157 if (!strcasecmp(a->name, argv[app])) {
03158
03159 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03160 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03161 int synopsis_size, description_size;
03162
03163 no_registered_app = 0;
03164
03165 if (a->synopsis)
03166 synopsis_size = strlen(a->synopsis) + 23;
03167 else
03168 synopsis_size = strlen("Not available") + 23;
03169 synopsis = alloca(synopsis_size);
03170
03171 if (a->description)
03172 description_size = strlen(a->description) + 23;
03173 else
03174 description_size = strlen("Not available") + 23;
03175 description = alloca(description_size);
03176
03177 if (synopsis && description) {
03178 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
03179 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03180 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03181 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03182 term_color(synopsis,
03183 a->synopsis ? a->synopsis : "Not available",
03184 COLOR_CYAN, 0, synopsis_size);
03185 term_color(description,
03186 a->description ? a->description : "Not available",
03187 COLOR_CYAN, 0, description_size);
03188
03189 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03190 } else {
03191
03192 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
03193 "[Synopsis]\n %s\n\n"
03194 "[Description]\n%s\n",
03195 a->name,
03196 a->synopsis ? a->synopsis : "Not available",
03197 a->description ? a->description : "Not available");
03198 }
03199 }
03200 }
03201 }
03202 AST_LIST_UNLOCK(&apps);
03203
03204
03205 if (no_registered_app) {
03206 ast_cli(fd, "Your application(s) is (are) not registered\n");
03207 return RESULT_FAILURE;
03208 }
03209
03210 return RESULT_SUCCESS;
03211 }
03212
03213 static int handle_show_application(int fd, int argc, char *argv[])
03214 {
03215 struct ast_app *a;
03216 int app, no_registered_app = 1;
03217
03218 if (argc < 4)
03219 return RESULT_SHOWUSAGE;
03220
03221
03222 AST_LIST_LOCK(&apps);
03223 AST_LIST_TRAVERSE(&apps, a, list) {
03224
03225
03226 for (app = 3; app < argc; app++) {
03227 if (!strcasecmp(a->name, argv[app])) {
03228
03229 char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03230 char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03231 int synopsis_size, description_size;
03232
03233 no_registered_app = 0;
03234
03235 if (a->synopsis)
03236 synopsis_size = strlen(a->synopsis) + 23;
03237 else
03238 synopsis_size = strlen("Not available") + 23;
03239 synopsis = alloca(synopsis_size);
03240
03241 if (a->description)
03242 description_size = strlen(a->description) + 23;
03243 else
03244 description_size = strlen("Not available") + 23;
03245 description = alloca(description_size);
03246
03247 if (synopsis && description) {
03248 snprintf(info, 64 + AST_MAX_APP, "\n -= Info about application '%s' =- \n\n", a->name);
03249 term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03250 term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03251 term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03252 term_color(synopsis,
03253 a->synopsis ? a->synopsis : "Not available",
03254 COLOR_CYAN, 0, synopsis_size);
03255 term_color(description,
03256 a->description ? a->description : "Not available",
03257 COLOR_CYAN, 0, description_size);
03258
03259 ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03260 } else {
03261
03262 ast_cli(fd,"\n -= Info about application '%s' =- \n\n"
03263 "[Synopsis]\n %s\n\n"
03264 "[Description]\n%s\n",
03265 a->name,
03266 a->synopsis ? a->synopsis : "Not available",
03267 a->description ? a->description : "Not available");
03268 }
03269 }
03270 }
03271 }
03272 AST_LIST_UNLOCK(&apps);
03273
03274
03275 if (no_registered_app) {
03276 ast_cli(fd, "Your application(s) is (are) not registered\n");
03277 return RESULT_FAILURE;
03278 }
03279
03280 return RESULT_SUCCESS;
03281 }
03282
03283
03284 static int handle_show_hints(int fd, int argc, char *argv[])
03285 {
03286 struct ast_hint *hint;
03287 int num = 0;
03288 int watchers;
03289 struct ast_state_cb *watcher;
03290
03291 if (AST_LIST_EMPTY(&hints)) {
03292 ast_cli(fd, "There are no registered dialplan hints\n");
03293 return RESULT_SUCCESS;
03294 }
03295
03296 ast_cli(fd, "\n -= Registered Asterisk Dial Plan Hints =-\n");
03297 AST_LIST_LOCK(&hints);
03298 AST_LIST_TRAVERSE(&hints, hint, list) {
03299 watchers = 0;
03300 for (watcher = hint->callbacks; watcher; watcher = watcher->next)
03301 watchers++;
03302 ast_cli(fd, " %20s@%-20.20s: %-20.20s State:%-15.15s Watchers %2d\n",
03303 ast_get_extension_name(hint->exten),
03304 ast_get_context_name(ast_get_extension_context(hint->exten)),
03305 ast_get_extension_app(hint->exten),
03306 ast_extension_state2str(hint->laststate), watchers);
03307 num++;
03308 }
03309 ast_cli(fd, "----------------\n");
03310 ast_cli(fd, "- %d hints registered\n", num);
03311 AST_LIST_UNLOCK(&hints);
03312 return RESULT_SUCCESS;
03313 }
03314
03315
03316 static int handle_show_switches(int fd, int argc, char *argv[])
03317 {
03318 struct ast_switch *sw;
03319
03320 AST_LIST_LOCK(&switches);
03321
03322 if (AST_LIST_EMPTY(&switches)) {
03323 AST_LIST_UNLOCK(&switches);
03324 ast_cli(fd, "There are no registered alternative switches\n");
03325 return RESULT_SUCCESS;
03326 }
03327
03328 ast_cli(fd, "\n -= Registered Asterisk Alternative Switches =-\n");
03329 AST_LIST_TRAVERSE(&switches, sw, list)
03330 ast_cli(fd, "%s: %s\n", sw->name, sw->description);
03331
03332 AST_LIST_UNLOCK(&switches);
03333
03334 return RESULT_SUCCESS;
03335 }
03336
03337
03338
03339
03340 static int handle_show_applications_deprecated(int fd, int argc, char *argv[])
03341 {
03342 struct ast_app *a;
03343 int like = 0, describing = 0;
03344 int total_match = 0;
03345 int total_apps = 0;
03346
03347 AST_LIST_LOCK(&apps);
03348
03349 if (AST_LIST_EMPTY(&apps)) {
03350 ast_cli(fd, "There are no registered applications\n");
03351 AST_LIST_UNLOCK(&apps);
03352 return -1;
03353 }
03354
03355
03356 if ((argc == 4) && (!strcmp(argv[2], "like"))) {
03357 like = 1;
03358 } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
03359 describing = 1;
03360 }
03361
03362
03363 if ((!like) && (!describing)) {
03364 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
03365 } else {
03366 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
03367 }
03368
03369 AST_LIST_TRAVERSE(&apps, a, list) {
03370 int printapp = 0;
03371 total_apps++;
03372 if (like) {
03373 if (strcasestr(a->name, argv[3])) {
03374 printapp = 1;
03375 total_match++;
03376 }
03377 } else if (describing) {
03378 if (a->description) {
03379
03380 int i;
03381 printapp = 1;
03382 for (i = 3; i < argc; i++) {
03383 if (!strcasestr(a->description, argv[i])) {
03384 printapp = 0;
03385 } else {
03386 total_match++;
03387 }
03388 }
03389 }
03390 } else {
03391 printapp = 1;
03392 }
03393
03394 if (printapp) {
03395 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03396 }
03397 }
03398 if ((!like) && (!describing)) {
03399 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
03400 } else {
03401 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
03402 }
03403
03404 AST_LIST_UNLOCK(&apps);
03405
03406 return RESULT_SUCCESS;
03407 }
03408 static int handle_show_applications(int fd, int argc, char *argv[])
03409 {
03410 struct ast_app *a;
03411 int like = 0, describing = 0;
03412 int total_match = 0;
03413 int total_apps = 0;
03414
03415 AST_LIST_LOCK(&apps);
03416
03417 if (AST_LIST_EMPTY(&apps)) {
03418 ast_cli(fd, "There are no registered applications\n");
03419 AST_LIST_UNLOCK(&apps);
03420 return -1;
03421 }
03422
03423
03424 if ((argc == 5) && (!strcmp(argv[3], "like"))) {
03425 like = 1;
03426 } else if ((argc > 4) && (!strcmp(argv[3], "describing"))) {
03427 describing = 1;
03428 }
03429
03430
03431 if ((!like) && (!describing)) {
03432 ast_cli(fd, " -= Registered Asterisk Applications =-\n");
03433 } else {
03434 ast_cli(fd, " -= Matching Asterisk Applications =-\n");
03435 }
03436
03437 AST_LIST_TRAVERSE(&apps, a, list) {
03438 int printapp = 0;
03439 total_apps++;
03440 if (like) {
03441 if (strcasestr(a->name, argv[4])) {
03442 printapp = 1;
03443 total_match++;
03444 }
03445 } else if (describing) {
03446 if (a->description) {
03447
03448 int i;
03449 printapp = 1;
03450 for (i = 4; i < argc; i++) {
03451 if (!strcasestr(a->description, argv[i])) {
03452 printapp = 0;
03453 } else {
03454 total_match++;
03455 }
03456 }
03457 }
03458 } else {
03459 printapp = 1;
03460 }
03461
03462 if (printapp) {
03463 ast_cli(fd," %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03464 }
03465 }
03466 if ((!like) && (!describing)) {
03467 ast_cli(fd, " -= %d Applications Registered =-\n",total_apps);
03468 } else {
03469 ast_cli(fd, " -= %d Applications Matching =-\n",total_match);
03470 }
03471
03472 AST_LIST_UNLOCK(&apps);
03473
03474 return RESULT_SUCCESS;
03475 }
03476
03477 static char *complete_show_applications_deprecated(const char *line, const char *word, int pos, int state)
03478 {
03479 static char* choices[] = { "like", "describing", NULL };
03480
03481 return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
03482 }
03483
03484 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
03485 {
03486 static char* choices[] = { "like", "describing", NULL };
03487
03488 return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
03489 }
03490
03491
03492
03493
03494 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
03495 int state)
03496 {
03497 struct ast_context *c = NULL;
03498 char *ret = NULL;
03499 int which = 0;
03500 int wordlen;
03501
03502
03503 if (pos != 2)
03504 return NULL;
03505
03506 ast_rdlock_contexts();
03507
03508 wordlen = strlen(word);
03509
03510
03511 while ( (c = ast_walk_contexts(c)) ) {
03512 if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
03513 ret = ast_strdup(ast_get_context_name(c));
03514 break;
03515 }
03516 }
03517
03518 ast_unlock_contexts();
03519
03520 return ret;
03521 }
03522
03523 struct dialplan_counters {
03524 int total_context;
03525 int total_exten;
03526 int total_prio;
03527 int context_existence;
03528 int extension_existence;
03529 };
03530
03531
03532 static void print_ext(struct ast_exten *e, char * buf, int buflen)
03533 {
03534 int prio = ast_get_extension_priority(e);
03535 if (prio == PRIORITY_HINT) {
03536 snprintf(buf, buflen, "hint: %s",
03537 ast_get_extension_app(e));
03538 } else {
03539 snprintf(buf, buflen, "%d. %s(%s)",
03540 prio, ast_get_extension_app(e),
03541 (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
03542 }
03543 }
03544
03545
03546 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[])
03547 {
03548 struct ast_context *c = NULL;
03549 int res = 0, old_total_exten = dpc->total_exten;
03550
03551 ast_rdlock_contexts();
03552
03553
03554 while ( (c = ast_walk_contexts(c)) ) {
03555 struct ast_exten *e;
03556 struct ast_include *i;
03557 struct ast_ignorepat *ip;
03558 char buf[256], buf2[256];
03559 int context_info_printed = 0;
03560
03561 if (context && strcmp(ast_get_context_name(c), context))
03562 continue;
03563
03564 dpc->context_existence = 1;
03565
03566 ast_lock_context(c);
03567
03568
03569
03570
03571
03572
03573
03574 if (!exten) {
03575 dpc->total_context++;
03576 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03577 ast_get_context_name(c), ast_get_context_registrar(c));
03578 context_info_printed = 1;
03579 }
03580
03581
03582 e = NULL;
03583 while ( (e = ast_walk_context_extensions(c, e)) ) {
03584 struct ast_exten *p;
03585
03586 if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
03587 continue;
03588
03589 dpc->extension_existence = 1;
03590
03591
03592 if (!context_info_printed) {
03593 dpc->total_context++;
03594 if (rinclude) {
03595 ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
03596 ast_get_context_name(c), ast_get_context_registrar(c));
03597 } else {
03598 ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03599 ast_get_context_name(c), ast_get_context_registrar(c));
03600 }
03601 context_info_printed = 1;
03602 }
03603 dpc->total_prio++;
03604
03605
03606 snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
03607
03608 print_ext(e, buf2, sizeof(buf2));
03609
03610 ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
03611 ast_get_extension_registrar(e));
03612
03613 dpc->total_exten++;
03614
03615 p = e;
03616 while ( (p = ast_walk_extension_priorities(e, p)) ) {
03617 const char *el = ast_get_extension_label(p);
03618 dpc->total_prio++;
03619 if (el)
03620 snprintf(buf, sizeof(buf), " [%s]", el);
03621 else
03622 buf[0] = '\0';
03623 print_ext(p, buf2, sizeof(buf2));
03624
03625 ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
03626 ast_get_extension_registrar(p));
03627 }
03628 }
03629
03630
03631 i = NULL;
03632 while ( (i = ast_walk_context_includes(c, i)) ) {
03633 snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
03634 if (exten) {
03635
03636 if (includecount >= AST_PBX_MAX_STACK) {
03637 ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
03638 } else {
03639 int dupe=0;
03640 int x;
03641 for (x=0;x<includecount;x++) {
03642 if (!strcasecmp(includes[x], ast_get_include_name(i))) {
03643 dupe++;
03644 break;
03645 }
03646 }
03647 if (!dupe) {
03648 includes[includecount] = ast_get_include_name(i);
03649 show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
03650 } else {
03651 ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
03652 }
03653 }
03654 } else {
03655 ast_cli(fd, " Include => %-45s [%s]\n",
03656 buf, ast_get_include_registrar(i));
03657 }
03658 }
03659
03660
03661 ip = NULL;
03662 while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
03663 const char *ipname = ast_get_ignorepat_name(ip);
03664 char ignorepat[AST_MAX_EXTENSION];
03665 snprintf(buf, sizeof(buf), "'%s'", ipname);
03666 snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03667 if (!exten || ast_extension_match(ignorepat, exten)) {
03668 ast_cli(fd, " Ignore pattern => %-45s [%s]\n",
03669 buf, ast_get_ignorepat_registrar(ip));
03670 }
03671 }
03672 if (!rinclude) {
03673 struct ast_sw *sw = NULL;
03674 while ( (sw = ast_walk_context_switches(c, sw)) ) {
03675 snprintf(buf, sizeof(buf), "'%s/%s'",
03676 ast_get_switch_name(sw),
03677 ast_get_switch_data(sw));
03678 ast_cli(fd, " Alt. Switch => %-45s [%s]\n",
03679 buf, ast_get_switch_registrar(sw));
03680 }
03681 }
03682
03683 ast_unlock_context(c);
03684
03685
03686 if (context_info_printed)
03687 ast_cli(fd, "\r\n");
03688 }
03689 ast_unlock_contexts();
03690
03691 return (dpc->total_exten == old_total_exten) ? -1 : res;
03692 }
03693
03694 static int handle_show_dialplan(int fd, int argc, char *argv[])
03695 {
03696 char *exten = NULL, *context = NULL;
03697
03698 struct dialplan_counters counters;
03699
03700 const char *incstack[AST_PBX_MAX_STACK];
03701 memset(&counters, 0, sizeof(counters));
03702
03703 if (argc != 2 && argc != 3)
03704 return RESULT_SHOWUSAGE;
03705
03706
03707 if (argc == 3) {
03708 if (strchr(argv[2], '@')) {
03709 context = ast_strdupa(argv[2]);
03710 exten = strsep(&context, "@");
03711
03712 if (ast_strlen_zero(exten))
03713 exten = NULL;
03714 } else {
03715 context = argv[2];
03716 }
03717 if (ast_strlen_zero(context))
03718 context = NULL;
03719 }
03720
03721 show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03722
03723
03724 if (context && !counters.context_existence) {
03725 ast_cli(fd, "There is no existence of '%s' context\n", context);
03726 return RESULT_FAILURE;
03727 }
03728
03729 if (exten && !counters.extension_existence) {
03730 if (context)
03731 ast_cli(fd, "There is no existence of %s@%s extension\n",
03732 exten, context);
03733 else
03734 ast_cli(fd,
03735 "There is no existence of '%s' extension in all contexts\n",
03736 exten);
03737 return RESULT_FAILURE;
03738 }
03739
03740 ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
03741 counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
03742 counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
03743 counters.total_context, counters.total_context == 1 ? "context" : "contexts");
03744
03745
03746 return RESULT_SUCCESS;
03747 }
03748
03749
03750 static int handle_show_globals(int fd, int argc, char *argv[])
03751 {
03752 int i = 0;
03753 struct ast_var_t *newvariable;
03754
03755 ast_mutex_lock(&globalslock);
03756 AST_LIST_TRAVERSE (&globals, newvariable, entries) {
03757 i++;
03758 ast_cli(fd, " %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
03759 }
03760 ast_mutex_unlock(&globalslock);
03761 ast_cli(fd, "\n -- %d variables\n", i);
03762
03763 return RESULT_SUCCESS;
03764 }
03765
03766
03767 static int handle_set_global_deprecated(int fd, int argc, char *argv[])
03768 {
03769 if (argc != 4)
03770 return RESULT_SHOWUSAGE;
03771
03772 pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
03773 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[2], argv[3]);
03774
03775 return RESULT_SUCCESS;
03776 }
03777
03778
03779 static int handle_set_global(int fd, int argc, char *argv[])
03780 {
03781 if (argc != 5)
03782 return RESULT_SHOWUSAGE;
03783
03784 pbx_builtin_setvar_helper(NULL, argv[3], argv[4]);
03785 ast_cli(fd, "\n -- Global variable %s set to %s\n", argv[3], argv[4]);
03786
03787 return RESULT_SUCCESS;
03788 }
03789
03790
03791
03792
03793
03794
03795 static struct ast_cli_entry cli_show_applications_deprecated = {
03796 { "show", "applications", NULL },
03797 handle_show_applications_deprecated, NULL,
03798 NULL, complete_show_applications_deprecated };
03799
03800 static struct ast_cli_entry cli_show_functions_deprecated = {
03801 { "show", "functions", NULL },
03802 handle_show_functions_deprecated, NULL,
03803 NULL };
03804
03805 static struct ast_cli_entry cli_show_switches_deprecated = {
03806 { "show", "switches", NULL },
03807 handle_show_switches, NULL,
03808 NULL };
03809
03810 static struct ast_cli_entry cli_show_hints_deprecated = {
03811 { "show", "hints", NULL },
03812 handle_show_hints, NULL,
03813 NULL };
03814
03815 static struct ast_cli_entry cli_show_globals_deprecated = {
03816 { "show", "globals", NULL },
03817 handle_show_globals, NULL,
03818 NULL };
03819
03820 static struct ast_cli_entry cli_show_function_deprecated = {
03821 { "show" , "function", NULL },
03822 handle_show_function_deprecated, NULL,
03823 NULL, complete_show_function };
03824
03825 static struct ast_cli_entry cli_show_application_deprecated = {
03826 { "show", "application", NULL },
03827 handle_show_application_deprecated, NULL,
03828 NULL, complete_show_application };
03829
03830 static struct ast_cli_entry cli_show_dialplan_deprecated = {
03831 { "show", "dialplan", NULL },
03832 handle_show_dialplan, NULL,
03833 NULL, complete_show_dialplan_context };
03834
03835 static struct ast_cli_entry cli_set_global_deprecated = {
03836 { "set", "global", NULL },
03837 handle_set_global_deprecated, NULL,
03838 NULL };
03839
03840 static struct ast_cli_entry pbx_cli[] = {
03841 { { "core", "show", "applications", NULL },
03842 handle_show_applications, "Shows registered dialplan applications",
03843 show_applications_help, complete_show_applications, &cli_show_applications_deprecated },
03844
03845 { { "core", "show", "functions", NULL },
03846 handle_show_functions, "Shows registered dialplan functions",
03847 show_functions_help, NULL, &cli_show_functions_deprecated },
03848
03849 { { "core", "show", "switches", NULL },
03850 handle_show_switches, "Show alternative switches",
03851 show_switches_help, NULL, &cli_show_switches_deprecated },
03852
03853 { { "core", "show", "hints", NULL },
03854 handle_show_hints, "Show dialplan hints",
03855 show_hints_help, NULL, &cli_show_hints_deprecated },
03856
03857 { { "core", "show", "globals", NULL },
03858 handle_show_globals, "Show global dialplan variables",
03859 show_globals_help, NULL, &cli_show_globals_deprecated },
03860
03861 { { "core", "show" , "function", NULL },
03862 handle_show_function, "Describe a specific dialplan function",
03863 show_function_help, complete_show_function, &cli_show_function_deprecated },
03864
03865 { { "core", "show", "application", NULL },
03866 handle_show_application, "Describe a specific dialplan application",
03867 show_application_help, complete_show_application, &cli_show_application_deprecated },
03868
03869 { { "core", "set", "global", NULL },
03870 handle_set_global, "Set global dialplan variable",
03871 set_global_help, NULL, &cli_set_global_deprecated },
03872
03873 { { "dialplan", "show", NULL },
03874 handle_show_dialplan, "Show dialplan",
03875 show_dialplan_help, complete_show_dialplan_context, &cli_show_dialplan_deprecated },
03876 };
03877
03878 int ast_unregister_application(const char *app)
03879 {
03880 struct ast_app *tmp;
03881
03882 AST_LIST_LOCK(&apps);
03883 AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
03884 if (!strcasecmp(app, tmp->name)) {
03885 AST_LIST_REMOVE_CURRENT(&apps, list);
03886 if (option_verbose > 1)
03887 ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
03888 free(tmp);
03889 break;
03890 }
03891 }
03892 AST_LIST_TRAVERSE_SAFE_END
03893 AST_LIST_UNLOCK(&apps);
03894
03895 return tmp ? 0 : -1;
03896 }
03897
03898 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
03899 {
03900 struct ast_context *tmp, **local_contexts;
03901 int length = sizeof(struct ast_context) + strlen(name) + 1;
03902
03903 if (!extcontexts) {
03904 ast_rdlock_contexts();
03905 local_contexts = &contexts;
03906 } else
03907 local_contexts = extcontexts;
03908
03909 for (tmp = *local_contexts; tmp; tmp = tmp->next) {
03910 if (!strcasecmp(tmp->name, name)) {
03911 if (!existsokay) {
03912 ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
03913 tmp = NULL;
03914 }
03915 if (!extcontexts)
03916 ast_unlock_contexts();
03917 return tmp;
03918 }
03919 }
03920
03921 if (!extcontexts)
03922 ast_unlock_contexts();
03923
03924 if ((tmp = ast_calloc(1, length))) {
03925 ast_mutex_init(&tmp->lock);
03926 ast_mutex_init(&tmp->macrolock);
03927 strcpy(tmp->name, name);
03928 tmp->registrar = registrar;
03929 if (!extcontexts)
03930 ast_wrlock_contexts();
03931 tmp->next = *local_contexts;
03932 *local_contexts = tmp;
03933 if (!extcontexts)
03934 ast_unlock_contexts();
03935 if (option_debug)
03936 ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
03937 if (option_verbose > 2)
03938 ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
03939 }
03940
03941 return tmp;
03942 }
03943
03944 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03945 {
03946 return __ast_context_create(extcontexts, name, registrar, 0);
03947 }
03948
03949 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03950 {
03951 return __ast_context_create(extcontexts, name, registrar, 1);
03952 }
03953 void __ast_context_destroy(struct ast_context *con, const char *registrar);
03954
03955 struct store_hint {
03956 char *context;
03957 char *exten;
03958 struct ast_state_cb *callbacks;
03959 int laststate;
03960 AST_LIST_ENTRY(store_hint) list;
03961 char data[1];
03962 };
03963
03964 AST_LIST_HEAD(store_hints, store_hint);
03965
03966
03967 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
03968 {
03969 struct ast_context *tmp, *lasttmp = NULL;
03970 struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
03971 struct store_hint *this;
03972 struct ast_hint *hint;
03973 struct ast_exten *exten;
03974 int length;
03975 struct ast_state_cb *thiscb, *prevcb;
03976
03977
03978
03979
03980
03981
03982
03983
03984
03985 ast_wrlock_contexts();
03986 AST_LIST_LOCK(&hints);
03987
03988
03989 AST_LIST_TRAVERSE(&hints, hint, list) {
03990 if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
03991 length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
03992 if (!(this = ast_calloc(1, length)))
03993 continue;
03994 this->callbacks = hint->callbacks;
03995 hint->callbacks = NULL;
03996 this->laststate = hint->laststate;
03997 this->context = this->data;
03998 strcpy(this->data, hint->exten->parent->name);
03999 this->exten = this->data + strlen(this->context) + 1;
04000 strcpy(this->exten, hint->exten->exten);
04001 AST_LIST_INSERT_HEAD(&store, this, list);
04002 }
04003 }
04004
04005 tmp = *extcontexts;
04006 if (registrar) {
04007
04008 if (option_debug)
04009 ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
04010 __ast_context_destroy(NULL,registrar);
04011 while (tmp) {
04012 lasttmp = tmp;
04013 tmp = tmp->next;
04014 }
04015 } else {
04016
04017 while (tmp) {
04018 ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
04019 __ast_context_destroy(tmp,tmp->registrar);
04020 lasttmp = tmp;
04021 tmp = tmp->next;
04022 }
04023 }
04024 if (lasttmp) {
04025 lasttmp->next = contexts;
04026 contexts = *extcontexts;
04027 *extcontexts = NULL;
04028 } else
04029 ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
04030
04031
04032
04033
04034 while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
04035 struct pbx_find_info q = { .stacklen = 0 };
04036 exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
04037
04038 AST_LIST_TRAVERSE(&hints, hint, list) {
04039 if (hint->exten == exten)
04040 break;
04041 }
04042 if (!exten || !hint) {
04043
04044 prevcb = NULL;
04045 thiscb = this->callbacks;
04046 while (thiscb) {
04047 prevcb = thiscb;
04048 thiscb = thiscb->next;
04049 prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
04050 free(prevcb);
04051 }
04052 } else {
04053 thiscb = this->callbacks;
04054 while (thiscb->next)
04055 thiscb = thiscb->next;
04056 thiscb->next = hint->callbacks;
04057 hint->callbacks = this->callbacks;
04058 hint->laststate = this->laststate;
04059 }
04060 free(this);
04061 }
04062
04063 AST_LIST_UNLOCK(&hints);
04064 ast_unlock_contexts();
04065
04066 return;
04067 }
04068
04069
04070
04071
04072
04073
04074 int ast_context_add_include(const char *context, const char *include, const char *registrar)
04075 {
04076 int ret = -1;
04077 struct ast_context *c = find_context_locked(context);
04078
04079 if (c) {
04080 ret = ast_context_add_include2(c, include, registrar);
04081 ast_unlock_contexts();
04082 }
04083 return ret;
04084 }
04085
04086
04087
04088
04089
04090 static int lookup_name(const char *s, char *const names[], int max)
04091 {
04092 int i;
04093
04094 if (names) {
04095 for (i = 0; names[i]; i++) {
04096 if (!strcasecmp(s, names[i]))
04097 return i+1;
04098 }
04099 } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
04100 return i;
04101 }
04102 return 0;
04103 }
04104
04105
04106
04107
04108 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
04109 {
04110 int s, e;
04111 unsigned int mask = 0;
04112
04113
04114 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
04115 s = 0;
04116 e = max - 1;
04117 } else {
04118
04119 char *c = strchr(src, '-');
04120 if (c)
04121 *c++ = '\0';
04122
04123 s = lookup_name(src, names, max);
04124 if (!s) {
04125 ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
04126 return 0;
04127 }
04128 s--;
04129 if (c) {
04130 e = lookup_name(c, names, max);
04131 if (!e) {
04132 ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
04133 return 0;
04134 }
04135 e--;
04136 } else
04137 e = s;
04138 }
04139
04140 mask = 1 << e;
04141 while (s != e) {
04142 if (s >= max) {
04143 s = 0;
04144 mask |= (1 << s);
04145 } else {
04146 mask |= (1 << s);
04147 s++;
04148 }
04149 }
04150 return mask;
04151 }
04152
04153
04154 static void get_timerange(struct ast_timing *i, char *times)
04155 {
04156 char *e;
04157 int x;
04158 int s1, s2;
04159 int e1, e2;
04160
04161
04162
04163 memset(i->minmask, 0, sizeof(i->minmask));
04164
04165
04166
04167 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
04168 for (x=0; x<24; x++)
04169 i->minmask[x] = 0x3fffffff;
04170 return;
04171 }
04172
04173 e = strchr(times, '-');
04174 if (!e) {
04175 ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
04176 return;
04177 }
04178 *e++ = '\0';
04179
04180 while (*e && !isdigit(*e))
04181 e++;
04182 if (!*e) {
04183 ast_log(LOG_WARNING, "Invalid time range. Assuming no restrictions based on time.\n");
04184 return;
04185 }
04186 if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
04187 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", times);
04188 return;
04189 }
04190 if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
04191 ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e);
04192 return;
04193 }
04194
04195 #if 1
04196 s1 = s1 * 30 + s2/2;
04197 if ((s1 < 0) || (s1 >= 24*30)) {
04198 ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
04199 return;
04200 }
04201 e1 = e1 * 30 + e2/2;
04202 if ((e1 < 0) || (e1 >= 24*30)) {
04203 ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
04204 return;
04205 }
04206
04207 for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
04208 i->minmask[x/30] |= (1 << (x % 30));
04209 }
04210
04211 i->minmask[x/30] |= (1 << (x % 30));
04212 #else
04213 for (cth=0; cth<24; cth++) {
04214
04215 i->minmask[cth] = 0;
04216 for (ctm=0; ctm<30; ctm++) {
04217 if (
04218
04219 (((cth == s1) && (ctm >= s2)) &&
04220 ((cth < e1)))
04221
04222 || (((cth == s1) && (ctm >= s2)) &&
04223 ((cth == e1) && (ctm <= e2)))
04224
04225 || ((cth > s1) &&
04226 (cth < e1))
04227
04228 || ((cth > s1) &&
04229 ((cth == e1) && (ctm <= e2)))
04230 )
04231 i->minmask[cth] |= (1 << (ctm / 2));
04232 }
04233 }
04234 #endif
04235
04236 return;
04237 }
04238
04239 static char *days[] =
04240 {
04241 "sun",
04242 "mon",
04243 "tue",
04244 "wed",
04245 "thu",
04246 "fri",
04247 "sat",
04248 NULL,
04249 };
04250
04251 static char *months[] =
04252 {
04253 "jan",
04254 "feb",
04255 "mar",
04256 "apr",
04257 "may",
04258 "jun",
04259 "jul",
04260 "aug",
04261 "sep",
04262 "oct",
04263 "nov",
04264 "dec",
04265 NULL,
04266 };
04267
04268 int ast_build_timing(struct ast_timing *i, const char *info_in)
04269 {
04270 char info_save[256];
04271 char *info;
04272
04273
04274 if (ast_strlen_zero(info_in))
04275 return 0;
04276
04277 ast_copy_string(info_save, info_in, sizeof(info_save));
04278 info = info_save;
04279
04280 i->monthmask = 0xfff;
04281 i->daymask = 0x7fffffffU;
04282 i->dowmask = 0x7f;
04283
04284 get_timerange(i, strsep(&info, "|"));
04285 if (info)
04286 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
04287 if (info)
04288 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
04289 if (info)
04290 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
04291 return 1;
04292 }
04293
04294 int ast_check_timing(const struct ast_timing *i)
04295 {
04296 struct tm tm;
04297 time_t t = time(NULL);
04298
04299 ast_localtime(&t, &tm, NULL);
04300
04301
04302 if (!(i->monthmask & (1 << tm.tm_mon)))
04303 return 0;
04304
04305
04306
04307 if (!(i->daymask & (1 << (tm.tm_mday-1))))
04308 return 0;
04309
04310
04311 if (!(i->dowmask & (1 << tm.tm_wday)))
04312 return 0;
04313
04314
04315 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
04316 ast_log(LOG_WARNING, "Insane time...\n");
04317 return 0;
04318 }
04319
04320
04321
04322 if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
04323 return 0;
04324
04325
04326 return 1;
04327 }
04328
04329
04330
04331
04332
04333
04334
04335
04336 int ast_context_add_include2(struct ast_context *con, const char *value,
04337 const char *registrar)
04338 {
04339 struct ast_include *new_include;
04340 char *c;
04341 struct ast_include *i, *il = NULL;
04342 int length;
04343 char *p;
04344
04345 length = sizeof(struct ast_include);
04346 length += 2 * (strlen(value) + 1);
04347
04348
04349 if (!(new_include = ast_calloc(1, length)))
04350 return -1;
04351
04352
04353
04354 p = new_include->stuff;
04355 new_include->name = p;
04356 strcpy(p, value);
04357 p += strlen(value) + 1;
04358 new_include->rname = p;
04359 strcpy(p, value);
04360
04361 if ( (c = strchr(p, '|')) ) {
04362 *c++ = '\0';
04363 new_include->hastime = ast_build_timing(&(new_include->timing), c);
04364 }
04365 new_include->next = NULL;
04366 new_include->registrar = registrar;
04367
04368 ast_mutex_lock(&con->lock);
04369
04370
04371 for (i = con->includes; i; i = i->next) {
04372 if (!strcasecmp(i->name, new_include->name)) {
04373 free(new_include);
04374 ast_mutex_unlock(&con->lock);
04375 errno = EEXIST;
04376 return -1;
04377 }
04378 il = i;
04379 }
04380
04381
04382 if (il)
04383 il->next = new_include;
04384 else
04385 con->includes = new_include;
04386 if (option_verbose > 2)
04387 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04388 ast_mutex_unlock(&con->lock);
04389
04390 return 0;
04391 }
04392
04393
04394
04395
04396
04397
04398 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
04399 {
04400 int ret = -1;
04401 struct ast_context *c = find_context_locked(context);
04402
04403 if (c) {
04404 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
04405 ast_unlock_contexts();
04406 }
04407 return ret;
04408 }
04409
04410
04411
04412
04413
04414
04415
04416
04417 int ast_context_add_switch2(struct ast_context *con, const char *value,
04418 const char *data, int eval, const char *registrar)
04419 {
04420 struct ast_sw *new_sw;
04421 struct ast_sw *i;
04422 int length;
04423 char *p;
04424
04425 length = sizeof(struct ast_sw);
04426 length += strlen(value) + 1;
04427 if (data)
04428 length += strlen(data);
04429 length++;
04430
04431
04432 if (!(new_sw = ast_calloc(1, length)))
04433 return -1;
04434
04435 p = new_sw->stuff;
04436 new_sw->name = p;
04437 strcpy(new_sw->name, value);
04438 p += strlen(value) + 1;
04439 new_sw->data = p;
04440 if (data) {
04441 strcpy(new_sw->data, data);
04442 p += strlen(data) + 1;
04443 } else {
04444 strcpy(new_sw->data, "");
04445 p++;
04446 }
04447 new_sw->eval = eval;
04448 new_sw->registrar = registrar;
04449
04450
04451 ast_mutex_lock(&con->lock);
04452
04453
04454 AST_LIST_TRAVERSE(&con->alts, i, list) {
04455 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04456 free(new_sw);
04457 ast_mutex_unlock(&con->lock);
04458 errno = EEXIST;
04459 return -1;
04460 }
04461 }
04462
04463
04464 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
04465
04466 if (option_verbose > 2)
04467 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04468
04469 ast_mutex_unlock(&con->lock);
04470
04471 return 0;
04472 }
04473
04474
04475
04476
04477
04478 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
04479 {
04480 int ret = -1;
04481 struct ast_context *c = find_context_locked(context);
04482
04483 if (c) {
04484 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
04485 ast_unlock_contexts();
04486 }
04487 return ret;
04488 }
04489
04490 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
04491 {
04492 struct ast_ignorepat *ip, *ipl = NULL;
04493
04494 ast_mutex_lock(&con->lock);
04495
04496 for (ip = con->ignorepats; ip; ip = ip->next) {
04497 if (!strcmp(ip->pattern, ignorepat) &&
04498 (!registrar || (registrar == ip->registrar))) {
04499 if (ipl) {
04500 ipl->next = ip->next;
04501 free(ip);
04502 } else {
04503 con->ignorepats = ip->next;
04504 free(ip);
04505 }
04506 ast_mutex_unlock(&con->lock);
04507 return 0;
04508 }
04509 ipl = ip;
04510 }
04511
04512 ast_mutex_unlock(&con->lock);
04513 errno = EINVAL;
04514 return -1;
04515 }
04516
04517
04518
04519
04520
04521 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
04522 {
04523 int ret = -1;
04524 struct ast_context *c = find_context_locked(context);
04525
04526 if (c) {
04527 ret = ast_context_add_ignorepat2(c, value, registrar);
04528 ast_unlock_contexts();
04529 }
04530 return ret;
04531 }
04532
04533 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04534 {
04535 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04536 int length;
04537 length = sizeof(struct ast_ignorepat);
04538 length += strlen(value) + 1;
04539 if (!(ignorepat = ast_calloc(1, length)))
04540 return -1;
04541
04542
04543
04544 strcpy((char *)ignorepat->pattern, value);
04545 ignorepat->next = NULL;
04546 ignorepat->registrar = registrar;
04547 ast_mutex_lock(&con->lock);
04548 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
04549 ignorepatl = ignorepatc;
04550 if (!strcasecmp(ignorepatc->pattern, value)) {
04551
04552 ast_mutex_unlock(&con->lock);
04553 errno = EEXIST;
04554 return -1;
04555 }
04556 }
04557 if (ignorepatl)
04558 ignorepatl->next = ignorepat;
04559 else
04560 con->ignorepats = ignorepat;
04561 ast_mutex_unlock(&con->lock);
04562 return 0;
04563
04564 }
04565
04566 int ast_ignore_pattern(const char *context, const char *pattern)
04567 {
04568 struct ast_context *con = ast_context_find(context);
04569 if (con) {
04570 struct ast_ignorepat *pat;
04571 for (pat = con->ignorepats; pat; pat = pat->next) {
04572 if (ast_extension_match(pat->pattern, pattern))
04573 return 1;
04574 }
04575 }
04576
04577 return 0;
04578 }
04579
04580
04581
04582
04583
04584
04585 int ast_add_extension(const char *context, int replace, const char *extension,
04586 int priority, const char *label, const char *callerid,
04587 const char *application, void *data, void (*datad)(void *), const char *registrar)
04588 {
04589 int ret = -1;
04590 struct ast_context *c = find_context_locked(context);
04591
04592 if (c) {
04593 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
04594 application, data, datad, registrar);
04595 ast_unlock_contexts();
04596 }
04597 return ret;
04598 }
04599
04600 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04601 {
04602 if (!chan)
04603 return -1;
04604
04605 ast_channel_lock(chan);
04606
04607 if (!ast_strlen_zero(context))
04608 ast_copy_string(chan->context, context, sizeof(chan->context));
04609 if (!ast_strlen_zero(exten))
04610 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
04611 if (priority > -1) {
04612 chan->priority = priority;
04613
04614 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
04615 chan->priority--;
04616 }
04617
04618 ast_channel_unlock(chan);
04619
04620 return 0;
04621 }
04622
04623 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04624 {
04625 int res = 0;
04626
04627 ast_channel_lock(chan);
04628
04629 if (chan->pbx) {
04630 ast_explicit_goto(chan, context, exten, priority);
04631 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
04632 } else {
04633
04634
04635
04636 struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
04637 if (!tmpchan) {
04638 res = -1;
04639 } else {
04640 if (chan->cdr) {
04641 ast_cdr_discard(tmpchan->cdr);
04642 tmpchan->cdr = ast_cdr_dup(chan->cdr);
04643 }
04644
04645 tmpchan->readformat = chan->readformat;
04646 tmpchan->writeformat = chan->writeformat;
04647
04648 ast_explicit_goto(tmpchan,
04649 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
04650
04651
04652 ast_channel_masquerade(tmpchan, chan);
04653
04654
04655 ast_channel_lock(tmpchan);
04656 ast_do_masquerade(tmpchan);
04657 ast_channel_unlock(tmpchan);
04658
04659 if (ast_pbx_start(tmpchan)) {
04660 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
04661 ast_hangup(tmpchan);
04662 res = -1;
04663 }
04664 }
04665 }
04666 ast_channel_unlock(chan);
04667 return res;
04668 }
04669
04670 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
04671 {
04672 struct ast_channel *chan;
04673 int res = -1;
04674
04675 chan = ast_get_channel_by_name_locked(channame);
04676 if (chan) {
04677 res = ast_async_goto(chan, context, exten, priority);
04678 ast_channel_unlock(chan);
04679 }
04680 return res;
04681 }
04682
04683
04684 static int ext_strncpy(char *dst, const char *src, int len)
04685 {
04686 int count=0;
04687
04688 while (*src && (count < len - 1)) {
04689 switch(*src) {
04690 case ' ':
04691
04692
04693
04694 break;
04695 default:
04696 *dst = *src;
04697 dst++;
04698 }
04699 src++;
04700 count++;
04701 }
04702 *dst = '\0';
04703
04704 return count;
04705 }
04706
04707
04708
04709
04710 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
04711 struct ast_exten *el, struct ast_exten *e, int replace)
04712 {
04713 struct ast_exten *ep;
04714
04715 for (ep = NULL; e ; ep = e, e = e->peer) {
04716 if (e->priority >= tmp->priority)
04717 break;
04718 }
04719 if (!e) {
04720 ep->peer = tmp;
04721 return 0;
04722 }
04723 if (e->priority == tmp->priority) {
04724
04725
04726 if (!replace) {
04727 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04728 if (tmp->datad)
04729 tmp->datad(tmp->data);
04730 free(tmp);
04731 return -1;
04732 }
04733
04734
04735
04736 tmp->next = e->next;
04737 tmp->peer = e->peer;
04738 if (ep)
04739 ep->peer = tmp;
04740 else if (el)
04741 el->next = tmp;
04742 else
04743 con->root = tmp;
04744 if (tmp->priority == PRIORITY_HINT)
04745 ast_change_hint(e,tmp);
04746
04747 if (e->datad)
04748 e->datad(e->data);
04749 free(e);
04750 } else {
04751 tmp->peer = e;
04752 tmp->next = e->next;
04753 if (ep)
04754 ep->peer = tmp;
04755 else {
04756 if (el)
04757 el->next = tmp;
04758 else
04759 con->root = tmp;
04760 e->next = NULL;
04761 }
04762
04763 if (tmp->priority == PRIORITY_HINT)
04764 ast_add_hint(tmp);
04765 }
04766 return 0;
04767 }
04768
04769
04770
04771
04772
04773
04774
04775
04776
04777
04778
04779
04780
04781
04782
04783
04784
04785
04786
04787
04788
04789
04790
04791
04792
04793
04794 int ast_add_extension2(struct ast_context *con,
04795 int replace, const char *extension, int priority, const char *label, const char *callerid,
04796 const char *application, void *data, void (*datad)(void *),
04797 const char *registrar)
04798 {
04799
04800
04801
04802
04803
04804
04805 struct ast_exten *tmp, *e, *el = NULL;
04806 int res;
04807 int length;
04808 char *p;
04809 char expand_buf[VAR_BUF_SIZE] = { 0, };
04810
04811
04812
04813
04814 ast_mutex_lock(&globalslock);
04815 if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04816 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04817 application = expand_buf;
04818 }
04819 ast_mutex_unlock(&globalslock);
04820
04821 length = sizeof(struct ast_exten);
04822 length += strlen(extension) + 1;
04823 length += strlen(application) + 1;
04824 if (label)
04825 length += strlen(label) + 1;
04826 if (callerid)
04827 length += strlen(callerid) + 1;
04828 else
04829 length ++;
04830
04831
04832 if (!(tmp = ast_calloc(1, length)))
04833 return -1;
04834
04835
04836 p = tmp->stuff;
04837 if (label) {
04838 tmp->label = p;
04839 strcpy(p, label);
04840 p += strlen(label) + 1;
04841 }
04842 tmp->exten = p;
04843 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
04844 tmp->priority = priority;
04845 tmp->cidmatch = p;
04846 if (callerid) {
04847 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
04848 tmp->matchcid = 1;
04849 } else {
04850 *p++ = '\0';
04851 tmp->matchcid = 0;
04852 }
04853 tmp->app = p;
04854 strcpy(p, application);
04855 tmp->parent = con;
04856 tmp->data = data;
04857 tmp->datad = datad;
04858 tmp->registrar = registrar;
04859
04860 ast_mutex_lock(&con->lock);
04861 res = 0;
04862 for (e = con->root; e; el = e, e = e->next) {
04863 res = ext_cmp(e->exten, extension);
04864 if (res == 0) {
04865 if (!e->matchcid && !tmp->matchcid)
04866 res = 0;
04867 else if (tmp->matchcid && !e->matchcid)
04868 res = 1;
04869 else if (e->matchcid && !tmp->matchcid)
04870 res = -1;
04871 else
04872 res = strcasecmp(e->cidmatch, tmp->cidmatch);
04873 }
04874 if (res >= 0)
04875 break;
04876 }
04877 if (e && res == 0) {
04878 res = add_pri(con, tmp, el, e, replace);
04879 ast_mutex_unlock(&con->lock);
04880 if (res < 0) {
04881 errno = EEXIST;
04882 return 0;
04883 }
04884 } else {
04885
04886
04887
04888
04889 tmp->next = e;
04890 if (el)
04891 el->next = tmp;
04892 else
04893 con->root = tmp;
04894 ast_mutex_unlock(&con->lock);
04895 if (tmp->priority == PRIORITY_HINT)
04896 ast_add_hint(tmp);
04897 }
04898 if (option_debug) {
04899 if (tmp->matchcid) {
04900 if (option_debug)
04901 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
04902 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04903 } else {
04904 if (option_debug)
04905 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
04906 tmp->exten, tmp->priority, con->name);
04907 }
04908 }
04909 if (option_verbose > 2) {
04910 if (tmp->matchcid) {
04911 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
04912 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04913 } else {
04914 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
04915 tmp->exten, tmp->priority, con->name);
04916 }
04917 }
04918 return 0;
04919 }
04920
04921 struct async_stat {
04922 pthread_t p;
04923 struct ast_channel *chan;
04924 char context[AST_MAX_CONTEXT];
04925 char exten[AST_MAX_EXTENSION];
04926 int priority;
04927 int timeout;
04928 char app[AST_MAX_EXTENSION];
04929 char appdata[1024];
04930 };
04931
04932 static void *async_wait(void *data)
04933 {
04934 struct async_stat *as = data;
04935 struct ast_channel *chan = as->chan;
04936 int timeout = as->timeout;
04937 int res;
04938 struct ast_frame *f;
04939 struct ast_app *app;
04940
04941 while (timeout && (chan->_state != AST_STATE_UP)) {
04942 res = ast_waitfor(chan, timeout);
04943 if (res < 1)
04944 break;
04945 if (timeout > -1)
04946 timeout = res;
04947 f = ast_read(chan);
04948 if (!f)
04949 break;
04950 if (f->frametype == AST_FRAME_CONTROL) {
04951 if ((f->subclass == AST_CONTROL_BUSY) ||
04952 (f->subclass == AST_CONTROL_CONGESTION) ) {
04953 ast_frfree(f);
04954 break;
04955 }
04956 }
04957 ast_frfree(f);
04958 }
04959 if (chan->_state == AST_STATE_UP) {
04960 if (!ast_strlen_zero(as->app)) {
04961 app = pbx_findapp(as->app);
04962 if (app) {
04963 if (option_verbose > 2)
04964 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04965 pbx_exec(chan, app, as->appdata);
04966 } else
04967 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04968 } else {
04969 if (!ast_strlen_zero(as->context))
04970 ast_copy_string(chan->context, as->context, sizeof(chan->context));
04971 if (!ast_strlen_zero(as->exten))
04972 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
04973 if (as->priority > 0)
04974 chan->priority = as->priority;
04975
04976 if (ast_pbx_run(chan)) {
04977 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04978 } else {
04979
04980 chan = NULL;
04981 }
04982 }
04983 }
04984 free(as);
04985 if (chan)
04986 ast_hangup(chan);
04987 return NULL;
04988 }
04989
04990
04991
04992
04993
04994
04995 static int ast_pbx_outgoing_cdr_failed(void)
04996 {
04997
04998 struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0);
04999
05000 if (!chan)
05001 return -1;
05002
05003 if (!chan->cdr) {
05004
05005 ast_channel_free(chan);
05006 return -1;
05007 }
05008
05009
05010 ast_cdr_init(chan->cdr, chan);
05011 ast_cdr_start(chan->cdr);
05012 ast_cdr_end(chan->cdr);
05013 ast_cdr_failed(chan->cdr);
05014 ast_cdr_detach(chan->cdr);
05015 ast_channel_free(chan);
05016
05017 return 0;
05018 }
05019
05020 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)
05021 {
05022 struct ast_channel *chan;
05023 struct async_stat *as;
05024 int res = -1, cdr_res = -1;
05025 struct outgoing_helper oh;
05026 pthread_attr_t attr;
05027
05028 if (sync) {
05029 LOAD_OH(oh);
05030 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05031 if (channel) {
05032 *channel = chan;
05033 if (chan)
05034 ast_channel_lock(chan);
05035 }
05036 if (chan) {
05037 if (chan->_state == AST_STATE_UP) {
05038 res = 0;
05039 if (option_verbose > 3)
05040 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05041
05042 if (sync > 1) {
05043 if (channel)
05044 ast_channel_unlock(chan);
05045 if (ast_pbx_run(chan)) {
05046 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05047 if (channel)
05048 *channel = NULL;
05049 ast_hangup(chan);
05050 chan = NULL;
05051 res = -1;
05052 }
05053 } else {
05054 if (ast_pbx_start(chan)) {
05055 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05056 if (channel) {
05057 *channel = NULL;
05058 ast_channel_unlock(chan);
05059 }
05060 ast_hangup(chan);
05061 res = -1;
05062 }
05063 chan = NULL;
05064 }
05065 } else {
05066 if (option_verbose > 3)
05067 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05068
05069 if (chan->cdr) {
05070
05071
05072 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05073 ast_cdr_failed(chan->cdr);
05074 }
05075
05076 if (channel) {
05077 *channel = NULL;
05078 ast_channel_unlock(chan);
05079 }
05080 ast_hangup(chan);
05081 chan = NULL;
05082 }
05083 }
05084
05085 if (res < 0) {
05086 if (*reason == 0) {
05087
05088 cdr_res = ast_pbx_outgoing_cdr_failed();
05089 if (cdr_res != 0) {
05090 res = cdr_res;
05091 goto outgoing_exten_cleanup;
05092 }
05093 }
05094
05095
05096
05097 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05098 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
05099 if (chan) {
05100 char failed_reason[4] = "";
05101 if (!ast_strlen_zero(context))
05102 ast_copy_string(chan->context, context, sizeof(chan->context));
05103 set_ext_pri(chan, "failed", 1);
05104 ast_set_variables(chan, vars);
05105 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
05106 pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
05107 if (account)
05108 ast_cdr_setaccount(chan, account);
05109 if (ast_pbx_run(chan)) {
05110 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05111 ast_hangup(chan);
05112 }
05113 chan = NULL;
05114 }
05115 }
05116 }
05117 } else {
05118 if (!(as = ast_calloc(1, sizeof(*as)))) {
05119 res = -1;
05120 goto outgoing_exten_cleanup;
05121 }
05122 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05123 if (channel) {
05124 *channel = chan;
05125 if (chan)
05126 ast_channel_lock(chan);
05127 }
05128 if (!chan) {
05129 free(as);
05130 res = -1;
05131 goto outgoing_exten_cleanup;
05132 }
05133 as->chan = chan;
05134 ast_copy_string(as->context, context, sizeof(as->context));
05135 set_ext_pri(as->chan, exten, priority);
05136 as->timeout = timeout;
05137 ast_set_variables(chan, vars);
05138 if (account)
05139 ast_cdr_setaccount(chan, account);
05140 pthread_attr_init(&attr);
05141 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05142 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05143 ast_log(LOG_WARNING, "Failed to start async wait\n");
05144 free(as);
05145 if (channel) {
05146 *channel = NULL;
05147 ast_channel_unlock(chan);
05148 }
05149 ast_hangup(chan);
05150 res = -1;
05151 pthread_attr_destroy(&attr);
05152 goto outgoing_exten_cleanup;
05153 }
05154 pthread_attr_destroy(&attr);
05155 res = 0;
05156 }
05157 outgoing_exten_cleanup:
05158 ast_variables_destroy(vars);
05159 return res;
05160 }
05161
05162 struct app_tmp {
05163 char app[256];
05164 char data[256];
05165 struct ast_channel *chan;
05166 pthread_t t;
05167 };
05168
05169
05170 static void *ast_pbx_run_app(void *data)
05171 {
05172 struct app_tmp *tmp = data;
05173 struct ast_app *app;
05174 app = pbx_findapp(tmp->app);
05175 if (app) {
05176 if (option_verbose > 3)
05177 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05178 pbx_exec(tmp->chan, app, tmp->data);
05179 } else
05180 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05181 ast_hangup(tmp->chan);
05182 free(tmp);
05183 return NULL;
05184 }
05185
05186 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)
05187 {
05188 struct ast_channel *chan;
05189 struct app_tmp *tmp;
05190 int res = -1, cdr_res = -1;
05191 struct outgoing_helper oh;
05192 pthread_attr_t attr;
05193
05194 memset(&oh, 0, sizeof(oh));
05195 oh.vars = vars;
05196 oh.account = account;
05197
05198 if (locked_channel)
05199 *locked_channel = NULL;
05200 if (ast_strlen_zero(app)) {
05201 res = -1;
05202 goto outgoing_app_cleanup;
05203 }
05204 if (sync) {
05205 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05206 if (chan) {
05207 if (!chan->cdr) {
05208 chan->cdr = ast_cdr_alloc();
05209 if(!chan->cdr) {
05210
05211 free(chan->pbx);
05212 res = -1;
05213 goto outgoing_app_cleanup;
05214 }
05215
05216 ast_cdr_init(chan->cdr, chan);
05217 ast_cdr_start(chan->cdr);
05218 }
05219 ast_set_variables(chan, vars);
05220 if (account)
05221 ast_cdr_setaccount(chan, account);
05222 if (chan->_state == AST_STATE_UP) {
05223 res = 0;
05224 if (option_verbose > 3)
05225 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05226 tmp = ast_calloc(1, sizeof(*tmp));
05227 if (!tmp)
05228 res = -1;
05229 else {
05230 ast_copy_string(tmp->app, app, sizeof(tmp->app));
05231 if (appdata)
05232 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05233 tmp->chan = chan;
05234 if (sync > 1) {
05235 if (locked_channel)
05236 ast_channel_unlock(chan);
05237 ast_pbx_run_app(tmp);
05238 } else {
05239 pthread_attr_init(&attr);
05240 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05241 if (locked_channel)
05242 ast_channel_lock(chan);
05243 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05244 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05245 free(tmp);
05246 if (locked_channel)
05247 ast_channel_unlock(chan);
05248 ast_hangup(chan);
05249 res = -1;
05250 } else {
05251 if (locked_channel)
05252 *locked_channel = chan;
05253 }
05254 pthread_attr_destroy(&attr);
05255 }
05256 }
05257 } else {
05258 if (option_verbose > 3)
05259 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05260 if (chan->cdr) {
05261
05262
05263 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05264 ast_cdr_failed(chan->cdr);
05265 }
05266 ast_hangup(chan);
05267 }
05268 }
05269
05270 if (res < 0) {
05271 if (*reason == 0) {
05272
05273 cdr_res = ast_pbx_outgoing_cdr_failed();
05274 if (cdr_res != 0) {
05275 res = cdr_res;
05276 goto outgoing_app_cleanup;
05277 }
05278 }
05279 }
05280
05281 } else {
05282 struct async_stat *as;
05283 if (!(as = ast_calloc(1, sizeof(*as)))) {
05284 res = -1;
05285 goto outgoing_app_cleanup;
05286 }
05287 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05288 if (!chan) {
05289 free(as);
05290 res = -1;
05291 goto outgoing_app_cleanup;
05292 }
05293 as->chan = chan;
05294 ast_copy_string(as->app, app, sizeof(as->app));
05295 if (appdata)
05296 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
05297 as->timeout = timeout;
05298 ast_set_variables(chan, vars);
05299 if (account)
05300 ast_cdr_setaccount(chan, account);
05301
05302 pthread_attr_init(&attr);
05303 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05304 if (locked_channel)
05305 ast_channel_lock(chan);
05306 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05307 ast_log(LOG_WARNING, "Failed to start async wait\n");
05308 free(as);
05309 if (locked_channel)
05310 ast_channel_unlock(chan);
05311 ast_hangup(chan);
05312 res = -1;
05313 pthread_attr_destroy(&attr);
05314 goto outgoing_app_cleanup;
05315 } else {
05316 if (locked_channel)
05317 *locked_channel = chan;
05318 }
05319 pthread_attr_destroy(&attr);
05320 res = 0;
05321 }
05322 outgoing_app_cleanup:
05323 ast_variables_destroy(vars);
05324 return res;
05325 }
05326
05327 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05328 {
05329 struct ast_context *tmp, *tmpl=NULL;
05330 struct ast_include *tmpi;
05331 struct ast_sw *sw;
05332 struct ast_exten *e, *el, *en;
05333 struct ast_ignorepat *ipi;
05334
05335 for (tmp = contexts; tmp; ) {
05336 struct ast_context *next;
05337 for (; tmp; tmpl = tmp, tmp = tmp->next) {
05338 if (option_debug)
05339 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
05340 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
05341 (!con || !strcasecmp(tmp->name, con->name)) )
05342 break;
05343 }
05344 if (!tmp)
05345 break;
05346 ast_mutex_lock(&tmp->lock);
05347 if (option_debug)
05348 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
05349 next = tmp->next;
05350 if (tmpl)
05351 tmpl->next = next;
05352 else
05353 contexts = next;
05354
05355
05356 ast_mutex_unlock(&tmp->lock);
05357 for (tmpi = tmp->includes; tmpi; ) {
05358 struct ast_include *tmpil = tmpi;
05359 tmpi = tmpi->next;
05360 free(tmpil);
05361 }
05362 for (ipi = tmp->ignorepats; ipi; ) {
05363 struct ast_ignorepat *ipl = ipi;
05364 ipi = ipi->next;
05365 free(ipl);
05366 }
05367 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
05368 free(sw);
05369 for (e = tmp->root; e;) {
05370 for (en = e->peer; en;) {
05371 el = en;
05372 en = en->peer;
05373 destroy_exten(el);
05374 }
05375 el = e;
05376 e = e->next;
05377 destroy_exten(el);
05378 }
05379 ast_mutex_destroy(&tmp->lock);
05380 free(tmp);
05381
05382 tmp = con ? NULL : next;
05383 }
05384 }
05385
05386 void ast_context_destroy(struct ast_context *con, const char *registrar)
05387 {
05388 ast_wrlock_contexts();
05389 __ast_context_destroy(con,registrar);
05390 ast_unlock_contexts();
05391 }
05392
05393 static void wait_for_hangup(struct ast_channel *chan, void *data)
05394 {
05395 int res;
05396 struct ast_frame *f;
05397 int waittime;
05398
05399 if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
05400 waittime = -1;
05401 if (waittime > -1) {
05402 ast_safe_sleep(chan, waittime * 1000);
05403 } else do {
05404 res = ast_waitfor(chan, -1);
05405 if (res < 0)
05406 return;
05407 f = ast_read(chan);
05408 if (f)
05409 ast_frfree(f);
05410 } while(f);
05411 }
05412
05413
05414
05415
05416 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05417 {
05418 ast_indicate(chan, AST_CONTROL_PROGRESS);
05419 return 0;
05420 }
05421
05422
05423
05424
05425 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05426 {
05427 ast_indicate(chan, AST_CONTROL_RINGING);
05428 return 0;
05429 }
05430
05431
05432
05433
05434 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05435 {
05436 ast_indicate(chan, AST_CONTROL_BUSY);
05437
05438
05439 if (chan->_state != AST_STATE_UP)
05440 ast_setstate(chan, AST_STATE_BUSY);
05441 wait_for_hangup(chan, data);
05442 return -1;
05443 }
05444
05445
05446
05447
05448 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
05449 {
05450 ast_indicate(chan, AST_CONTROL_CONGESTION);
05451
05452
05453 if (chan->_state != AST_STATE_UP)
05454 ast_setstate(chan, AST_STATE_BUSY);
05455 wait_for_hangup(chan, data);
05456 return -1;
05457 }
05458
05459
05460
05461
05462 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05463 {
05464 int delay = 0;
05465 int res;
05466
05467 if (chan->_state == AST_STATE_UP)
05468 delay = 0;
05469 else if (!ast_strlen_zero(data))
05470 delay = atoi(data);
05471
05472 res = ast_answer(chan);
05473 if (res)
05474 return res;
05475
05476 if (delay)
05477 res = ast_safe_sleep(chan, delay);
05478
05479 return res;
05480 }
05481
05482 AST_APP_OPTIONS(resetcdr_opts, {
05483 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05484 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05485 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05486 });
05487
05488
05489
05490
05491 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05492 {
05493 char *args;
05494 struct ast_flags flags = { 0 };
05495
05496 if (!ast_strlen_zero(data)) {
05497 args = ast_strdupa(data);
05498 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05499 }
05500
05501 ast_cdr_reset(chan->cdr, &flags);
05502
05503 return 0;
05504 }
05505
05506
05507
05508
05509 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05510 {
05511
05512 ast_cdr_setamaflags(chan, data ? data : "");
05513 return 0;
05514 }
05515
05516
05517
05518
05519 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05520 {
05521 if (!ast_strlen_zero(data)) {
05522 int cause;
05523 char *endptr;
05524
05525 if ((cause = ast_str2cause(data)) > -1) {
05526 chan->hangupcause = cause;
05527 return -1;
05528 }
05529
05530 cause = strtol((const char *) data, &endptr, 10);
05531 if (cause != 0 || (data != endptr)) {
05532 chan->hangupcause = cause;
05533 return -1;
05534 }
05535
05536 ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
05537 }
05538
05539 if (!chan->hangupcause) {
05540 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05541 }
05542
05543 return -1;
05544 }
05545
05546
05547
05548
05549 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05550 {
05551 int res=0;
05552 char *s, *ts;
05553 struct ast_timing timing;
05554
05555 if (ast_strlen_zero(data)) {
05556 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05557 return -1;
05558 }
05559
05560 ts = s = ast_strdupa(data);
05561
05562
05563 strsep(&ts,"?");
05564
05565
05566 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05567 res = pbx_builtin_goto(chan, ts);
05568
05569 return res;
05570 }
05571
05572
05573
05574
05575 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05576 {
05577 char *s, *appname;
05578 struct ast_timing timing;
05579 struct ast_app *app;
05580 static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05581
05582 if (ast_strlen_zero(data)) {
05583 ast_log(LOG_WARNING, "%s\n", usage);
05584 return -1;
05585 }
05586
05587 appname = ast_strdupa(data);
05588
05589 s = strsep(&appname,"?");
05590 if (!appname) {
05591 ast_log(LOG_WARNING, "%s\n", usage);
05592 return -1;
05593 }
05594
05595 if (!ast_build_timing(&timing, s)) {
05596 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
05597 return -1;
05598 }
05599
05600 if (!ast_check_timing(&timing))
05601 return 0;
05602
05603
05604 if ((s = strchr(appname, '|')))
05605 *s++ = '\0';
05606
05607 if ((app = pbx_findapp(appname))) {
05608 return pbx_exec(chan, app, S_OR(s, ""));
05609 } else {
05610 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
05611 return -1;
05612 }
05613 }
05614
05615
05616
05617
05618 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05619 {
05620 double s;
05621 int ms;
05622
05623
05624 if (data && (s = atof(data)) > 0) {
05625 ms = s * 1000.0;
05626 return ast_safe_sleep(chan, ms);
05627 }
05628 return 0;
05629 }
05630
05631
05632
05633
05634 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05635 {
05636 int ms, res;
05637 double sec;
05638 struct ast_flags flags = {0};
05639 char *opts[1] = { NULL };
05640 char *parse;
05641 AST_DECLARE_APP_ARGS(args,
05642 AST_APP_ARG(timeout);
05643 AST_APP_ARG(options);
05644 );
05645
05646 if (!ast_strlen_zero(data)) {
05647 parse = ast_strdupa(data);
05648 AST_STANDARD_APP_ARGS(args, parse);
05649 } else
05650 memset(&args, 0, sizeof(args));
05651
05652 if (args.options)
05653 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
05654
05655 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
05656 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
05657 } else if (ast_test_flag(&flags, WAITEXTEN_MOH))
05658 ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
05659
05660
05661 if (args.timeout && (sec = atof(args.timeout)) > 0.0)
05662 ms = 1000 * sec;
05663 else if (chan->pbx)
05664 ms = chan->pbx->rtimeout * 1000;
05665 else
05666 ms = 10000;
05667 res = ast_waitfordigit(chan, ms);
05668 if (!res) {
05669 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05670 if (option_verbose > 2)
05671 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05672 } else if (chan->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
05673 if (option_verbose > 2)
05674 ast_verbose(VERBOSE_PREFIX_3 "Call timeout on %s, checking for 'T'\n", chan->name);
05675 res = -1;
05676 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05677 if (option_verbose > 2)
05678 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05679 set_ext_pri(chan, "t", 0);
05680 } else {
05681 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05682 res = -1;
05683 }
05684 }
05685
05686 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05687 ast_indicate(chan, AST_CONTROL_UNHOLD);
05688
05689 return res;
05690 }
05691
05692
05693
05694
05695 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05696 {
05697 int res = 0;
05698 struct ast_flags flags = {0};
05699 char *parse;
05700 AST_DECLARE_APP_ARGS(args,
05701 AST_APP_ARG(filename);
05702 AST_APP_ARG(options);
05703 AST_APP_ARG(lang);
05704 AST_APP_ARG(context);
05705 );
05706
05707 if (ast_strlen_zero(data)) {
05708 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05709 return -1;
05710 }
05711
05712 parse = ast_strdupa(data);
05713
05714 AST_STANDARD_APP_ARGS(args, parse);
05715
05716 if (ast_strlen_zero(args.lang))
05717 args.lang = (char *)chan->language;
05718
05719 if (ast_strlen_zero(args.context))
05720 args.context = chan->context;
05721
05722 if (args.options) {
05723 if (!strcasecmp(args.options, "skip"))
05724 flags.flags = BACKGROUND_SKIP;
05725 else if (!strcasecmp(args.options, "noanswer"))
05726 flags.flags = BACKGROUND_NOANSWER;
05727 else
05728 ast_app_parse_options(background_opts, &flags, NULL, args.options);
05729 }
05730
05731
05732 if (chan->_state != AST_STATE_UP) {
05733 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05734 return 0;
05735 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05736 res = ast_answer(chan);
05737 }
05738 }
05739
05740 if (!res) {
05741 char *back = args.filename;
05742 char *front;
05743 ast_stopstream(chan);
05744
05745 while (!res && (front = strsep(&back, "&")) ) {
05746 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
05747 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05748 res = 0;
05749 break;
05750 }
05751 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05752 res = ast_waitstream(chan, "");
05753 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05754 res = ast_waitstream_exten(chan, args.context);
05755 } else {
05756 res = ast_waitstream(chan, AST_DIGIT_ANY);
05757 }
05758 ast_stopstream(chan);
05759 }
05760 }
05761 if (args.context != chan->context && res) {
05762 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05763 ast_copy_string(chan->context, args.context, sizeof(chan->context));
05764 chan->priority = 0;
05765 res = 0;
05766 }
05767 return res;
05768 }
05769
05770
05771
05772
05773 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05774 {
05775 int res = ast_parseable_goto(chan, data);
05776 if (!res && (option_verbose > 2))
05777 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05778 return res;
05779 }
05780
05781
05782 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05783 {
05784 struct ast_var_t *variables;
05785 const char *var, *val;
05786 int total = 0;
05787
05788 if (!chan)
05789 return 0;
05790
05791 memset(buf, 0, size);
05792
05793 ast_channel_lock(chan);
05794
05795 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05796 if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
05797
05798 ) {
05799 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05800 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05801 break;
05802 } else
05803 total++;
05804 } else
05805 break;
05806 }
05807
05808 ast_channel_unlock(chan);
05809
05810 return total;
05811 }
05812
05813 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05814 {
05815 struct ast_var_t *variables;
05816 const char *ret = NULL;
05817 int i;
05818 struct varshead *places[2] = { NULL, &globals };
05819
05820 if (!name)
05821 return NULL;
05822
05823 if (chan) {
05824 ast_channel_lock(chan);
05825 places[0] = &chan->varshead;
05826 }
05827
05828 for (i = 0; i < 2; i++) {
05829 if (!places[i])
05830 continue;
05831 if (places[i] == &globals)
05832 ast_mutex_lock(&globalslock);
05833 AST_LIST_TRAVERSE(places[i], variables, entries) {
05834 if (!strcmp(name, ast_var_name(variables))) {
05835 ret = ast_var_value(variables);
05836 break;
05837 }
05838 }
05839 if (places[i] == &globals)
05840 ast_mutex_unlock(&globalslock);
05841 if (ret)
05842 break;
05843 }
05844
05845 if (chan)
05846 ast_channel_unlock(chan);
05847
05848 return ret;
05849 }
05850
05851 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05852 {
05853 struct ast_var_t *newvariable;
05854 struct varshead *headp;
05855
05856 if (name[strlen(name)-1] == ')') {
05857 char *function = ast_strdupa(name);
05858
05859 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05860 ast_func_write(chan, function, value);
05861 return;
05862 }
05863
05864 if (chan) {
05865 ast_channel_lock(chan);
05866 headp = &chan->varshead;
05867 } else {
05868 ast_mutex_lock(&globalslock);
05869 headp = &globals;
05870 }
05871
05872 if (value) {
05873 if ((option_verbose > 1) && (headp == &globals))
05874 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05875 newvariable = ast_var_assign(name, value);
05876 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05877 }
05878
05879 if (chan)
05880 ast_channel_unlock(chan);
05881 else
05882 ast_mutex_unlock(&globalslock);
05883 }
05884
05885 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
05886 {
05887 struct ast_var_t *newvariable;
05888 struct varshead *headp;
05889 const char *nametail = name;
05890
05891 if (name[strlen(name)-1] == ')') {
05892 char *function = ast_strdupa(name);
05893
05894 ast_func_write(chan, function, value);
05895 return;
05896 }
05897
05898 if (chan) {
05899 ast_channel_lock(chan);
05900 headp = &chan->varshead;
05901 } else {
05902 ast_mutex_lock(&globalslock);
05903 headp = &globals;
05904 }
05905
05906
05907 if (*nametail == '_') {
05908 nametail++;
05909 if (*nametail == '_')
05910 nametail++;
05911 }
05912
05913 AST_LIST_TRAVERSE (headp, newvariable, entries) {
05914 if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
05915
05916 AST_LIST_REMOVE(headp, newvariable, entries);
05917 ast_var_delete(newvariable);
05918 break;
05919 }
05920 }
05921
05922 if (value) {
05923 if ((option_verbose > 1) && (headp == &globals))
05924 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05925 newvariable = ast_var_assign(name, value);
05926 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05927 }
05928
05929 if (chan)
05930 ast_channel_unlock(chan);
05931 else
05932 ast_mutex_unlock(&globalslock);
05933 }
05934
05935 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
05936 {
05937 char *name, *value, *mydata;
05938 int argc;
05939 char *argv[24];
05940 int global = 0;
05941 int x;
05942
05943 if (ast_strlen_zero(data)) {
05944 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
05945 return 0;
05946 }
05947
05948 mydata = ast_strdupa(data);
05949 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
05950
05951
05952 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
05953 argc--;
05954 if (strchr(argv[argc], 'g')) {
05955 ast_log(LOG_WARNING, "The use of the 'g' flag is deprecated. Please use Set(GLOBAL(foo)=bar) instead\n");
05956 global = 1;
05957 }
05958 }
05959
05960 if (argc > 1)
05961 ast_log(LOG_WARNING, "Setting multiple variables at once within Set is deprecated. Please separate each name/value pair into its own line.\n");
05962
05963 for (x = 0; x < argc; x++) {
05964 name = argv[x];
05965 if ((value = strchr(name, '='))) {
05966 *value++ = '\0';
05967 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
05968 } else
05969 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
05970 }
05971
05972 return(0);
05973 }
05974
05975 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
05976 {
05977 char *name;
05978 char *value;
05979 char *channel;
05980 char tmp[VAR_BUF_SIZE]="";
05981
05982 if (ast_strlen_zero(data)) {
05983 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
05984 return 0;
05985 }
05986
05987 value = ast_strdupa(data);
05988 name = strsep(&value,"=");
05989 channel = strsep(&value,"|");
05990 if (channel && value && name) {
05991 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
05992 if (chan2) {
05993 char *s = alloca(strlen(value) + 4);
05994 if (s) {
05995 sprintf(s, "${%s}", value);
05996 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
05997 }
05998 ast_channel_unlock(chan2);
05999 }
06000 pbx_builtin_setvar_helper(chan, name, tmp);
06001 }
06002
06003 return(0);
06004 }
06005
06006
06007 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
06008 {
06009 char *name;
06010 char *stringp = data;
06011 static int dep_warning = 0;
06012
06013 if (ast_strlen_zero(data)) {
06014 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06015 return 0;
06016 }
06017
06018 name = strsep(&stringp, "=");
06019
06020 if (!dep_warning) {
06021 dep_warning = 1;
06022 ast_log(LOG_WARNING, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
06023 }
06024
06025
06026 pbx_builtin_setvar_helper(NULL, name, stringp);
06027
06028 return(0);
06029 }
06030
06031 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
06032 {
06033 return 0;
06034 }
06035
06036 void pbx_builtin_clear_globals(void)
06037 {
06038 struct ast_var_t *vardata;
06039
06040 ast_mutex_lock(&globalslock);
06041 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
06042 ast_var_delete(vardata);
06043 ast_mutex_unlock(&globalslock);
06044 }
06045
06046 int pbx_checkcondition(const char *condition)
06047 {
06048 if (ast_strlen_zero(condition))
06049 return 0;
06050 else if (*condition >= '0' && *condition <= '9')
06051 return atoi(condition);
06052 else
06053 return 1;
06054 }
06055
06056 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
06057 {
06058 char *condition, *branch1, *branch2, *branch;
06059 int rc;
06060 char *stringp;
06061
06062 if (ast_strlen_zero(data)) {
06063 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
06064 return 0;
06065 }
06066
06067 stringp = ast_strdupa(data);
06068 condition = strsep(&stringp,"?");
06069 branch1 = strsep(&stringp,":");
06070 branch2 = strsep(&stringp,"");
06071 branch = pbx_checkcondition(condition) ? branch1 : branch2;
06072
06073 if (ast_strlen_zero(branch)) {
06074 if (option_debug)
06075 ast_log(LOG_DEBUG, "Not taking any branch\n");
06076 return 0;
06077 }
06078
06079 rc = pbx_builtin_goto(chan, branch);
06080
06081 return rc;
06082 }
06083
06084 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
06085 {
06086 char tmp[256];
06087 char *number = tmp;
06088 char *options;
06089
06090 if (ast_strlen_zero(data)) {
06091 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06092 return -1;
06093 }
06094 ast_copy_string(tmp, data, sizeof(tmp));
06095 strsep(&number, "|");
06096 options = strsep(&number, "|");
06097 if (options) {
06098 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06099 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06100 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06101 return -1;
06102 }
06103 }
06104
06105 if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
06106 ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
06107 }
06108
06109 return 0;
06110 }
06111
06112 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06113 {
06114 int res = 0;
06115
06116 if (data)
06117 res = ast_say_digit_str(chan, data, "", chan->language);
06118 return res;
06119 }
06120
06121 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06122 {
06123 int res = 0;
06124
06125 if (data)
06126 res = ast_say_character_str(chan, data, "", chan->language);
06127 return res;
06128 }
06129
06130 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06131 {
06132 int res = 0;
06133
06134 if (data)
06135 res = ast_say_phonetic_str(chan, data, "", chan->language);
06136 return res;
06137 }
06138
06139 static int pbx_builtin_saydate(struct ast_channel *chan, void *data)
06140 {
06141 int res = 0;
06142 char *parse;
06143 int unixdate = 0;
06144 char charascii[2];
06145
06146 AST_DECLARE_APP_ARGS(args,
06147 AST_APP_ARG(datestr);
06148 AST_APP_ARG(digits);
06149 );
06150
06151
06152 if (ast_strlen_zero(data)) {
06153 ast_log(LOG_WARNING, "SayDate requires an argument (date)\n");
06154 return -1;
06155 }
06156
06157 if (!(parse = ast_strdupa(data))) {
06158 ast_log(LOG_WARNING, "Memory Error!\n");
06159 return -1;
06160 }
06161
06162 AST_STANDARD_APP_ARGS(args, parse);
06163
06164 if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
06165 ast_log(LOG_WARNING, "SayDate escape digits must be a subset from '0123456789*#'\n");
06166 args.digits = "";
06167 }
06168
06169 if (sscanf(args.datestr, "%d", &unixdate) != 1) {
06170 ast_log(LOG_WARNING, "Firt argument to SayDate must be numeric (date)\n");
06171 return -1;
06172 }
06173
06174 res = ast_say_date(chan, (time_t)unixdate, args.digits, chan->language);
06175 if (res > 0) {
06176 if (isdigit(res) || (res == '*') || (res == '#')) {
06177 snprintf(charascii, 2, "%c", res);
06178 pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
06179 res = 0;
06180 } else {
06181 ast_log(LOG_WARNING, "SayDate: invalid return value (%d) detected\n", res);
06182 }
06183 }
06184 return res;
06185 }
06186
06187 static int pbx_builtin_saytime(struct ast_channel *chan, void *data)
06188 {
06189 int res = 0;
06190 char *parse;
06191 int secs = 0;
06192 char charascii[2];
06193
06194 AST_DECLARE_APP_ARGS(args,
06195 AST_APP_ARG(timestr);
06196 AST_APP_ARG(digits);
06197 );
06198
06199 if (ast_strlen_zero(data)) {
06200 ast_log(LOG_WARNING, "SayTime requires an argument (time in seconds)\n");
06201 return -1;
06202 }
06203
06204 if (!(parse = ast_strdupa(data))) {
06205 ast_log(LOG_WARNING, "Memory Error!\n");
06206 return -1;
06207 }
06208
06209 AST_STANDARD_APP_ARGS(args, parse);
06210
06211 if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
06212 ast_log(LOG_WARNING, "SayTime escape digits must be a subset from '0123456789*#'\n");
06213 args.digits = "";
06214 }
06215
06216 if (sscanf(args.timestr, "%d", &secs) != 1) {
06217 ast_log(LOG_WARNING, "Firt argument to SayTime must be numeric (time in seconds)\n");
06218 return -1;
06219 }
06220
06221 res = ast_say_time(chan, (time_t)secs, args.digits, chan->language);
06222 if (res > 0) {
06223 if (isdigit(res) || (res == '*') || (res == '#')) {
06224 snprintf(charascii, 2, "%c", res);
06225 pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
06226 res = 0;
06227 } else {
06228 ast_log(LOG_WARNING, "SayTime: invalid return value (%d) detected\n", res);
06229 }
06230 }
06231 return res;
06232 }
06233
06234 int load_pbx(void)
06235 {
06236 int x;
06237
06238
06239 if (option_verbose) {
06240 ast_verbose( "Asterisk PBX Core Initializing\n");
06241 ast_verbose( "Registering builtin applications:\n");
06242 }
06243 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
06244
06245
06246 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06247 if (option_verbose)
06248 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06249 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06250 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06251 return -1;
06252 }
06253 }
06254 return 0;
06255 }
06256
06257
06258
06259
06260 int ast_lock_contexts()
06261 {
06262 return ast_rwlock_wrlock(&conlock);
06263 }
06264
06265 int ast_rdlock_contexts(void)
06266 {
06267 return ast_rwlock_rdlock(&conlock);
06268 }
06269
06270 int ast_wrlock_contexts(void)
06271 {
06272 return ast_rwlock_wrlock(&conlock);
06273 }
06274
06275 int ast_unlock_contexts()
06276 {
06277 return ast_rwlock_unlock(&conlock);
06278 }
06279
06280
06281
06282
06283 int ast_lock_context(struct ast_context *con)
06284 {
06285 return ast_mutex_lock(&con->lock);
06286 }
06287
06288 int ast_unlock_context(struct ast_context *con)
06289 {
06290 return ast_mutex_unlock(&con->lock);
06291 }
06292
06293
06294
06295
06296 const char *ast_get_context_name(struct ast_context *con)
06297 {
06298 return con ? con->name : NULL;
06299 }
06300
06301 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
06302 {
06303 return exten ? exten->parent : NULL;
06304 }
06305
06306 const char *ast_get_extension_name(struct ast_exten *exten)
06307 {
06308 return exten ? exten->exten : NULL;
06309 }
06310
06311 const char *ast_get_extension_label(struct ast_exten *exten)
06312 {
06313 return exten ? exten->label : NULL;
06314 }
06315
06316 const char *ast_get_include_name(struct ast_include *inc)
06317 {
06318 return inc ? inc->name : NULL;
06319 }
06320
06321 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06322 {
06323 return ip ? ip->pattern : NULL;
06324 }
06325
06326 int ast_get_extension_priority(struct ast_exten *exten)
06327 {
06328 return exten ? exten->priority : -1;
06329 }
06330
06331
06332
06333
06334 const char *ast_get_context_registrar(struct ast_context *c)
06335 {
06336 return c ? c->registrar : NULL;
06337 }
06338
06339 const char *ast_get_extension_registrar(struct ast_exten *e)
06340 {
06341 return e ? e->registrar : NULL;
06342 }
06343
06344 const char *ast_get_include_registrar(struct ast_include *i)
06345 {
06346 return i ? i->registrar : NULL;
06347 }
06348
06349 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06350 {
06351 return ip ? ip->registrar : NULL;
06352 }
06353
06354 int ast_get_extension_matchcid(struct ast_exten *e)
06355 {
06356 return e ? e->matchcid : 0;
06357 }
06358
06359 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06360 {
06361 return e ? e->cidmatch : NULL;
06362 }
06363
06364 const char *ast_get_extension_app(struct ast_exten *e)
06365 {
06366 return e ? e->app : NULL;
06367 }
06368
06369 void *ast_get_extension_app_data(struct ast_exten *e)
06370 {
06371 return e ? e->data : NULL;
06372 }
06373
06374 const char *ast_get_switch_name(struct ast_sw *sw)
06375 {
06376 return sw ? sw->name : NULL;
06377 }
06378
06379 const char *ast_get_switch_data(struct ast_sw *sw)
06380 {
06381 return sw ? sw->data : NULL;
06382 }
06383
06384 const char *ast_get_switch_registrar(struct ast_sw *sw)
06385 {
06386 return sw ? sw->registrar : NULL;
06387 }
06388
06389
06390
06391
06392 struct ast_context *ast_walk_contexts(struct ast_context *con)
06393 {
06394 return con ? con->next : contexts;
06395 }
06396
06397 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06398 struct ast_exten *exten)
06399 {
06400 if (!exten)
06401 return con ? con->root : NULL;
06402 else
06403 return exten->next;
06404 }
06405
06406 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06407 struct ast_sw *sw)
06408 {
06409 if (!sw)
06410 return con ? AST_LIST_FIRST(&con->alts) : NULL;
06411 else
06412 return AST_LIST_NEXT(sw, list);
06413 }
06414
06415 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06416 struct ast_exten *priority)
06417 {
06418 return priority ? priority->peer : exten;
06419 }
06420
06421 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06422 struct ast_include *inc)
06423 {
06424 if (!inc)
06425 return con ? con->includes : NULL;
06426 else
06427 return inc->next;
06428 }
06429
06430 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06431 struct ast_ignorepat *ip)
06432 {
06433 if (!ip)
06434 return con ? con->ignorepats : NULL;
06435 else
06436 return ip->next;
06437 }
06438
06439 int ast_context_verify_includes(struct ast_context *con)
06440 {
06441 struct ast_include *inc = NULL;
06442 int res = 0;
06443
06444 while ( (inc = ast_walk_context_includes(con, inc)) ) {
06445 if (ast_context_find(inc->rname))
06446 continue;
06447
06448 res = -1;
06449 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
06450 ast_get_context_name(con), inc->rname);
06451 break;
06452 }
06453
06454 return res;
06455 }
06456
06457
06458 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
06459 {
06460 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06461
06462 if (!chan)
06463 return -2;
06464
06465 if (context == NULL)
06466 context = chan->context;
06467 if (exten == NULL)
06468 exten = chan->exten;
06469
06470 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06471 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
06472 return goto_func(chan, context, exten, priority);
06473 else
06474 return -3;
06475 }
06476
06477 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
06478 {
06479 return __ast_goto_if_exists(chan, context, exten, priority, 0);
06480 }
06481
06482 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
06483 {
06484 return __ast_goto_if_exists(chan, context, exten, priority, 1);
06485 }
06486
06487 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06488 {
06489 char *exten, *pri, *context;
06490 char *stringp;
06491 int ipri;
06492 int mode = 0;
06493
06494 if (ast_strlen_zero(goto_string)) {
06495 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06496 return -1;
06497 }
06498 stringp = ast_strdupa(goto_string);
06499 context = strsep(&stringp, "|");
06500 exten = strsep(&stringp, "|");
06501 pri = strsep(&stringp, "|");
06502 if (!exten) {
06503 pri = context;
06504 exten = NULL;
06505 context = NULL;
06506 } else if (!pri) {
06507 pri = exten;
06508 exten = context;
06509 context = NULL;
06510 }
06511 if (*pri == '+') {
06512 mode = 1;
06513 pri++;
06514 } else if (*pri == '-') {
06515 mode = -1;
06516 pri++;
06517 }
06518 if (sscanf(pri, "%d", &ipri) != 1) {
06519 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
06520 pri, chan->cid.cid_num)) < 1) {
06521 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06522 return -1;
06523 } else
06524 mode = 0;
06525 }
06526
06527
06528 if (mode)
06529 ipri = chan->priority + (ipri * mode);
06530
06531 ast_explicit_goto(chan, context, exten, ipri);
06532 ast_cdr_update(chan);
06533 return 0;
06534
06535 }