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