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