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