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 && *s > '9') {
04208 for (i = 0; names[i]; i++) {
04209 if (!strcasecmp(s, names[i])) {
04210 return i;
04211 }
04212 }
04213 }
04214
04215 if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
04216
04217 return i - 1;
04218 }
04219 return -1;
04220 }
04221
04222
04223
04224
04225 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
04226 {
04227 int start, end;
04228 unsigned int mask = 0;
04229 char *part;
04230
04231
04232 if (ast_strlen_zero(src) || !strcmp(src, "*")) {
04233 return (1 << max) - 1;
04234 }
04235
04236 while ((part = strsep(&src, "&"))) {
04237
04238 char *endpart = strchr(part, '-');
04239 if (endpart) {
04240 *endpart++ = '\0';
04241 }
04242
04243 if ((start = lookup_name(part, names, max)) < 0) {
04244 ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
04245 continue;
04246 }
04247 if (endpart) {
04248 if ((end = lookup_name(endpart, names, max)) < 0) {
04249 ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
04250 continue;
04251 }
04252 } else {
04253 end = start;
04254 }
04255
04256 mask |= (1 << end);
04257 while (start != end) {
04258 mask |= (1 << start);
04259 if (++start >= max) {
04260 start = 0;
04261 }
04262 }
04263 }
04264 return mask;
04265 }
04266
04267
04268 static void get_timerange(struct ast_timing *i, char *times)
04269 {
04270 char *endpart, *part;
04271 int x;
04272 int st_h, st_m;
04273 int endh, endm;
04274 int minute_start, minute_end;
04275
04276
04277 memset(i->minmask, 0, sizeof(i->minmask));
04278
04279
04280
04281 if (ast_strlen_zero(times) || !strcmp(times, "*")) {
04282
04283 for (x = 0; x < 48; x++) {
04284 i->minmask[x] = 0x3fffffff;
04285 }
04286 return;
04287 }
04288
04289 while ((part = strsep(×, "&"))) {
04290 if (!(endpart = strchr(part, '-'))) {
04291 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
04292 ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
04293 continue;
04294 }
04295 i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
04296 continue;
04297 }
04298 *endpart++ = '\0';
04299
04300 while (*endpart && !isdigit(*endpart)) {
04301 endpart++;
04302 }
04303 if (!*endpart) {
04304 ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
04305 continue;
04306 }
04307 if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
04308 ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
04309 continue;
04310 }
04311 if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
04312 ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
04313 continue;
04314 }
04315 minute_start = st_h * 60 + st_m;
04316 minute_end = endh * 60 + endm;
04317
04318 for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
04319 i->minmask[x / 30] |= (1 << (x % 30));
04320 }
04321
04322 i->minmask[x / 30] |= (1 << (x % 30));
04323 }
04324
04325 return;
04326 }
04327
04328 static char *days[] =
04329 {
04330 "sun",
04331 "mon",
04332 "tue",
04333 "wed",
04334 "thu",
04335 "fri",
04336 "sat",
04337 NULL,
04338 };
04339
04340 static char *months[] =
04341 {
04342 "jan",
04343 "feb",
04344 "mar",
04345 "apr",
04346 "may",
04347 "jun",
04348 "jul",
04349 "aug",
04350 "sep",
04351 "oct",
04352 "nov",
04353 "dec",
04354 NULL,
04355 };
04356
04357 int ast_build_timing(struct ast_timing *i, const char *info_in)
04358 {
04359 char info_save[256];
04360 char *info;
04361
04362
04363 if (ast_strlen_zero(info_in))
04364 return 0;
04365
04366 ast_copy_string(info_save, info_in, sizeof(info_save));
04367 info = info_save;
04368
04369 i->monthmask = 0xfff;
04370 i->daymask = 0x7fffffffU;
04371 i->dowmask = 0x7f;
04372
04373 get_timerange(i, strsep(&info, "|"));
04374 if (info)
04375 i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
04376 if (info)
04377 i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
04378 if (info)
04379 i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
04380 return 1;
04381 }
04382
04383 int ast_check_timing(const struct ast_timing *i)
04384 {
04385 struct tm tm;
04386 time_t t = time(NULL);
04387
04388 ast_localtime(&t, &tm, NULL);
04389
04390
04391 if (!(i->monthmask & (1 << tm.tm_mon)))
04392 return 0;
04393
04394
04395
04396 if (!(i->daymask & (1 << (tm.tm_mday-1))))
04397 return 0;
04398
04399
04400 if (!(i->dowmask & (1 << tm.tm_wday)))
04401 return 0;
04402
04403
04404 if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
04405 ast_log(LOG_WARNING, "Insane time...\n");
04406 return 0;
04407 }
04408
04409
04410
04411 if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
04412 return 0;
04413
04414
04415 return 1;
04416 }
04417
04418
04419
04420
04421
04422
04423
04424
04425 int ast_context_add_include2(struct ast_context *con, const char *value,
04426 const char *registrar)
04427 {
04428 struct ast_include *new_include;
04429 char *c;
04430 struct ast_include *i, *il = NULL;
04431 int length;
04432 char *p;
04433
04434 length = sizeof(struct ast_include);
04435 length += 2 * (strlen(value) + 1);
04436
04437
04438 if (!(new_include = ast_calloc(1, length)))
04439 return -1;
04440
04441
04442
04443 p = new_include->stuff;
04444 new_include->name = p;
04445 strcpy(p, value);
04446 p += strlen(value) + 1;
04447 new_include->rname = p;
04448 strcpy(p, value);
04449
04450 if ( (c = strchr(p, '|')) ) {
04451 *c++ = '\0';
04452 new_include->hastime = ast_build_timing(&(new_include->timing), c);
04453 }
04454 new_include->next = NULL;
04455 new_include->registrar = registrar;
04456
04457 ast_mutex_lock(&con->lock);
04458
04459
04460 for (i = con->includes; i; i = i->next) {
04461 if (!strcasecmp(i->name, new_include->name)) {
04462 free(new_include);
04463 ast_mutex_unlock(&con->lock);
04464 errno = EEXIST;
04465 return -1;
04466 }
04467 il = i;
04468 }
04469
04470
04471 if (il)
04472 il->next = new_include;
04473 else
04474 con->includes = new_include;
04475 if (option_verbose > 2)
04476 ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04477 ast_mutex_unlock(&con->lock);
04478
04479 return 0;
04480 }
04481
04482
04483
04484
04485
04486
04487 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
04488 {
04489 int ret = -1;
04490 struct ast_context *c = find_context_locked(context);
04491
04492 if (c) {
04493 ret = ast_context_add_switch2(c, sw, data, eval, registrar);
04494 ast_unlock_contexts();
04495 }
04496 return ret;
04497 }
04498
04499
04500
04501
04502
04503
04504
04505
04506 int ast_context_add_switch2(struct ast_context *con, const char *value,
04507 const char *data, int eval, const char *registrar)
04508 {
04509 struct ast_sw *new_sw;
04510 struct ast_sw *i;
04511 int length;
04512 char *p;
04513
04514 length = sizeof(struct ast_sw);
04515 length += strlen(value) + 1;
04516 if (data)
04517 length += strlen(data);
04518 length++;
04519
04520
04521 if (!(new_sw = ast_calloc(1, length)))
04522 return -1;
04523
04524 p = new_sw->stuff;
04525 new_sw->name = p;
04526 strcpy(new_sw->name, value);
04527 p += strlen(value) + 1;
04528 new_sw->data = p;
04529 if (data) {
04530 strcpy(new_sw->data, data);
04531 p += strlen(data) + 1;
04532 } else {
04533 strcpy(new_sw->data, "");
04534 p++;
04535 }
04536 new_sw->eval = eval;
04537 new_sw->registrar = registrar;
04538
04539
04540 ast_mutex_lock(&con->lock);
04541
04542
04543 AST_LIST_TRAVERSE(&con->alts, i, list) {
04544 if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04545 free(new_sw);
04546 ast_mutex_unlock(&con->lock);
04547 errno = EEXIST;
04548 return -1;
04549 }
04550 }
04551
04552
04553 AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
04554
04555 if (option_verbose > 2)
04556 ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04557
04558 ast_mutex_unlock(&con->lock);
04559
04560 return 0;
04561 }
04562
04563
04564
04565
04566
04567 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
04568 {
04569 int ret = -1;
04570 struct ast_context *c = find_context_locked(context);
04571
04572 if (c) {
04573 ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
04574 ast_unlock_contexts();
04575 }
04576 return ret;
04577 }
04578
04579 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
04580 {
04581 struct ast_ignorepat *ip, *ipl = NULL;
04582
04583 ast_mutex_lock(&con->lock);
04584
04585 for (ip = con->ignorepats; ip; ip = ip->next) {
04586 if (!strcmp(ip->pattern, ignorepat) &&
04587 (!registrar || (registrar == ip->registrar))) {
04588 if (ipl) {
04589 ipl->next = ip->next;
04590 free(ip);
04591 } else {
04592 con->ignorepats = ip->next;
04593 free(ip);
04594 }
04595 ast_mutex_unlock(&con->lock);
04596 return 0;
04597 }
04598 ipl = ip;
04599 }
04600
04601 ast_mutex_unlock(&con->lock);
04602 errno = EINVAL;
04603 return -1;
04604 }
04605
04606
04607
04608
04609
04610 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
04611 {
04612 int ret = -1;
04613 struct ast_context *c = find_context_locked(context);
04614
04615 if (c) {
04616 ret = ast_context_add_ignorepat2(c, value, registrar);
04617 ast_unlock_contexts();
04618 }
04619 return ret;
04620 }
04621
04622 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04623 {
04624 struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04625 int length;
04626 char *pattern;
04627 length = sizeof(struct ast_ignorepat);
04628 length += strlen(value) + 1;
04629 if (!(ignorepat = ast_calloc(1, length)))
04630 return -1;
04631
04632
04633
04634
04635
04636
04637 pattern = (char *) ignorepat->pattern;
04638 strcpy(pattern, value);
04639 ignorepat->next = NULL;
04640 ignorepat->registrar = registrar;
04641 ast_mutex_lock(&con->lock);
04642 for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
04643 ignorepatl = ignorepatc;
04644 if (!strcasecmp(ignorepatc->pattern, value)) {
04645
04646 ast_mutex_unlock(&con->lock);
04647 errno = EEXIST;
04648 return -1;
04649 }
04650 }
04651 if (ignorepatl)
04652 ignorepatl->next = ignorepat;
04653 else
04654 con->ignorepats = ignorepat;
04655 ast_mutex_unlock(&con->lock);
04656 return 0;
04657
04658 }
04659
04660 int ast_ignore_pattern(const char *context, const char *pattern)
04661 {
04662 struct ast_context *con = ast_context_find(context);
04663 if (con) {
04664 struct ast_ignorepat *pat;
04665 for (pat = con->ignorepats; pat; pat = pat->next) {
04666 if (ast_extension_match(pat->pattern, pattern))
04667 return 1;
04668 }
04669 }
04670
04671 return 0;
04672 }
04673
04674
04675
04676
04677
04678
04679 int ast_add_extension(const char *context, int replace, const char *extension,
04680 int priority, const char *label, const char *callerid,
04681 const char *application, void *data, void (*datad)(void *), const char *registrar)
04682 {
04683 int ret = -1;
04684 struct ast_context *c = find_context_locked(context);
04685
04686 if (c) {
04687 ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
04688 application, data, datad, registrar);
04689 ast_unlock_contexts();
04690 }
04691 return ret;
04692 }
04693
04694 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04695 {
04696 if (!chan)
04697 return -1;
04698
04699 ast_channel_lock(chan);
04700
04701 if (!ast_strlen_zero(context))
04702 ast_copy_string(chan->context, context, sizeof(chan->context));
04703 if (!ast_strlen_zero(exten))
04704 ast_copy_string(chan->exten, exten, sizeof(chan->exten));
04705 if (priority > -1) {
04706 chan->priority = priority;
04707
04708 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
04709 chan->priority--;
04710 }
04711
04712 ast_channel_unlock(chan);
04713
04714 return 0;
04715 }
04716
04717 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04718 {
04719 int res = 0;
04720
04721 ast_channel_lock(chan);
04722
04723 if (chan->pbx) {
04724 ast_explicit_goto(chan, context, exten, priority);
04725 ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
04726 } else {
04727
04728
04729
04730 struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
04731 if (!tmpchan) {
04732 res = -1;
04733 } else {
04734 if (chan->cdr) {
04735 ast_cdr_discard(tmpchan->cdr);
04736 tmpchan->cdr = ast_cdr_dup(chan->cdr);
04737 }
04738
04739 tmpchan->readformat = chan->readformat;
04740 tmpchan->writeformat = chan->writeformat;
04741
04742 ast_explicit_goto(tmpchan,
04743 S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
04744
04745
04746 if (ast_channel_masquerade(tmpchan, chan)) {
04747
04748
04749 ast_hangup(tmpchan);
04750 tmpchan = NULL;
04751 res = -1;
04752 } else {
04753
04754 ast_channel_lock(tmpchan);
04755 ast_do_masquerade(tmpchan);
04756 ast_channel_unlock(tmpchan);
04757
04758 if (ast_pbx_start(tmpchan)) {
04759 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
04760 ast_hangup(tmpchan);
04761 res = -1;
04762 }
04763 }
04764 }
04765 }
04766 ast_channel_unlock(chan);
04767 return res;
04768 }
04769
04770 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
04771 {
04772 struct ast_channel *chan;
04773 int res = -1;
04774
04775 chan = ast_get_channel_by_name_locked(channame);
04776 if (chan) {
04777 res = ast_async_goto(chan, context, exten, priority);
04778 ast_channel_unlock(chan);
04779 }
04780 return res;
04781 }
04782
04783
04784 static int ext_strncpy(char *dst, const char *src, int len)
04785 {
04786 int count=0;
04787
04788 while (*src && (count < len - 1)) {
04789 switch(*src) {
04790 case ' ':
04791
04792
04793
04794 break;
04795 default:
04796 *dst = *src;
04797 dst++;
04798 }
04799 src++;
04800 count++;
04801 }
04802 *dst = '\0';
04803
04804 return count;
04805 }
04806
04807
04808
04809
04810 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
04811 struct ast_exten *el, struct ast_exten *e, int replace)
04812 {
04813 struct ast_exten *ep;
04814
04815 for (ep = NULL; e ; ep = e, e = e->peer) {
04816 if (e->priority >= tmp->priority)
04817 break;
04818 }
04819 if (!e) {
04820 ep->peer = tmp;
04821 return 0;
04822 }
04823 if (e->priority == tmp->priority) {
04824
04825
04826 if (!replace) {
04827 ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04828 if (tmp->datad)
04829 tmp->datad(tmp->data);
04830 free(tmp);
04831 return -1;
04832 }
04833
04834
04835
04836 tmp->next = e->next;
04837 tmp->peer = e->peer;
04838 if (ep)
04839 ep->peer = tmp;
04840 else if (el)
04841 el->next = tmp;
04842 else
04843 con->root = tmp;
04844 if (tmp->priority == PRIORITY_HINT)
04845 ast_change_hint(e,tmp);
04846
04847 if (e->datad)
04848 e->datad(e->data);
04849 free(e);
04850 } else {
04851 tmp->peer = e;
04852 tmp->next = e->next;
04853 if (ep)
04854 ep->peer = tmp;
04855 else {
04856 if (el)
04857 el->next = tmp;
04858 else
04859 con->root = tmp;
04860 e->next = NULL;
04861 }
04862
04863 if (tmp->priority == PRIORITY_HINT)
04864 ast_add_hint(tmp);
04865 }
04866 return 0;
04867 }
04868
04869
04870
04871
04872
04873
04874
04875
04876
04877
04878
04879
04880
04881
04882
04883
04884
04885
04886
04887
04888
04889
04890
04891
04892
04893
04894 int ast_add_extension2(struct ast_context *con,
04895 int replace, const char *extension, int priority, const char *label, const char *callerid,
04896 const char *application, void *data, void (*datad)(void *),
04897 const char *registrar)
04898 {
04899
04900
04901
04902
04903
04904
04905 struct ast_exten *tmp, *e, *el = NULL;
04906 int res;
04907 int length;
04908 char *p;
04909 char expand_buf[VAR_BUF_SIZE] = { 0, };
04910
04911
04912
04913
04914 ast_mutex_lock(&globalslock);
04915 if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04916 pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04917 application = expand_buf;
04918 }
04919 ast_mutex_unlock(&globalslock);
04920
04921 length = sizeof(struct ast_exten);
04922 length += strlen(extension) + 1;
04923 length += strlen(application) + 1;
04924 if (label)
04925 length += strlen(label) + 1;
04926 if (callerid)
04927 length += strlen(callerid) + 1;
04928 else
04929 length ++;
04930
04931
04932 if (!(tmp = ast_calloc(1, length)))
04933 return -1;
04934
04935
04936 p = tmp->stuff;
04937 if (label) {
04938 tmp->label = p;
04939 strcpy(p, label);
04940 p += strlen(label) + 1;
04941 }
04942 tmp->exten = p;
04943 p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
04944 tmp->priority = priority;
04945 tmp->cidmatch = p;
04946 if (callerid) {
04947 p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
04948 tmp->matchcid = 1;
04949 } else {
04950 *p++ = '\0';
04951 tmp->matchcid = 0;
04952 }
04953 tmp->app = p;
04954 strcpy(p, application);
04955 tmp->parent = con;
04956 tmp->data = data;
04957 tmp->datad = datad;
04958 tmp->registrar = registrar;
04959
04960 ast_mutex_lock(&con->lock);
04961 res = 0;
04962 for (e = con->root; e; el = e, e = e->next) {
04963 res = ext_cmp(e->exten, tmp->exten);
04964 if (res == 0) {
04965 if (!e->matchcid && !tmp->matchcid)
04966 res = 0;
04967 else if (tmp->matchcid && !e->matchcid)
04968 res = 1;
04969 else if (e->matchcid && !tmp->matchcid)
04970 res = -1;
04971 else
04972 res = ext_cmp(e->cidmatch, tmp->cidmatch);
04973 }
04974 if (res >= 0)
04975 break;
04976 }
04977 if (e && res == 0) {
04978 res = add_pri(con, tmp, el, e, replace);
04979 ast_mutex_unlock(&con->lock);
04980 if (res < 0) {
04981 errno = EEXIST;
04982 return 0;
04983 }
04984 } else {
04985
04986
04987
04988
04989 tmp->next = e;
04990 if (el)
04991 el->next = tmp;
04992 else
04993 con->root = tmp;
04994 ast_mutex_unlock(&con->lock);
04995 if (tmp->priority == PRIORITY_HINT)
04996 ast_add_hint(tmp);
04997 }
04998 if (option_debug) {
04999 if (tmp->matchcid) {
05000 if (option_debug)
05001 ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
05002 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
05003 } else {
05004 if (option_debug)
05005 ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
05006 tmp->exten, tmp->priority, con->name);
05007 }
05008 }
05009 if (option_verbose > 2) {
05010 if (tmp->matchcid) {
05011 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
05012 tmp->exten, tmp->priority, tmp->cidmatch, con->name);
05013 } else {
05014 ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
05015 tmp->exten, tmp->priority, con->name);
05016 }
05017 }
05018 return 0;
05019 }
05020
05021 struct async_stat {
05022 pthread_t p;
05023 struct ast_channel *chan;
05024 char context[AST_MAX_CONTEXT];
05025 char exten[AST_MAX_EXTENSION];
05026 int priority;
05027 int timeout;
05028 char app[AST_MAX_EXTENSION];
05029 char appdata[1024];
05030 };
05031
05032 static void *async_wait(void *data)
05033 {
05034 struct async_stat *as = data;
05035 struct ast_channel *chan = as->chan;
05036 int timeout = as->timeout;
05037 int res;
05038 struct ast_frame *f;
05039 struct ast_app *app;
05040
05041 while (timeout && (chan->_state != AST_STATE_UP)) {
05042 res = ast_waitfor(chan, timeout);
05043 if (res < 1)
05044 break;
05045 if (timeout > -1)
05046 timeout = res;
05047 f = ast_read(chan);
05048 if (!f)
05049 break;
05050 if (f->frametype == AST_FRAME_CONTROL) {
05051 if ((f->subclass == AST_CONTROL_BUSY) ||
05052 (f->subclass == AST_CONTROL_CONGESTION) ) {
05053 ast_frfree(f);
05054 break;
05055 }
05056 }
05057 ast_frfree(f);
05058 }
05059 if (chan->_state == AST_STATE_UP) {
05060 if (!ast_strlen_zero(as->app)) {
05061 app = pbx_findapp(as->app);
05062 if (app) {
05063 if (option_verbose > 2)
05064 ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
05065 pbx_exec(chan, app, as->appdata);
05066 } else
05067 ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
05068 } else {
05069 if (!ast_strlen_zero(as->context))
05070 ast_copy_string(chan->context, as->context, sizeof(chan->context));
05071 if (!ast_strlen_zero(as->exten))
05072 ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
05073 if (as->priority > 0)
05074 chan->priority = as->priority;
05075
05076 if (ast_pbx_run(chan)) {
05077 ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
05078 } else {
05079
05080 chan = NULL;
05081 }
05082 }
05083 }
05084 free(as);
05085 if (chan)
05086 ast_hangup(chan);
05087 return NULL;
05088 }
05089
05090
05091
05092
05093
05094
05095 static int ast_pbx_outgoing_cdr_failed(void)
05096 {
05097
05098 struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
05099
05100 if (!chan)
05101 return -1;
05102
05103 if (!chan->cdr) {
05104
05105 ast_channel_free(chan);
05106 return -1;
05107 }
05108
05109
05110 ast_cdr_init(chan->cdr, chan);
05111 ast_cdr_start(chan->cdr);
05112 ast_cdr_end(chan->cdr);
05113 ast_cdr_failed(chan->cdr);
05114 ast_cdr_detach(chan->cdr);
05115 chan->cdr = NULL;
05116 ast_channel_free(chan);
05117
05118 return 0;
05119 }
05120
05121 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)
05122 {
05123 struct ast_channel *chan;
05124 struct async_stat *as;
05125 int res = -1, cdr_res = -1;
05126 struct outgoing_helper oh;
05127 pthread_attr_t attr;
05128
05129 if (sync) {
05130 LOAD_OH(oh);
05131 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05132 if (channel) {
05133 *channel = chan;
05134 if (chan)
05135 ast_channel_lock(chan);
05136 }
05137 if (chan) {
05138 if (chan->_state == AST_STATE_UP) {
05139 res = 0;
05140 if (option_verbose > 3)
05141 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05142
05143 if (sync > 1) {
05144 if (channel)
05145 ast_channel_unlock(chan);
05146 if (ast_pbx_run(chan)) {
05147 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05148 if (channel)
05149 *channel = NULL;
05150 ast_hangup(chan);
05151 chan = NULL;
05152 res = -1;
05153 }
05154 } else {
05155 if (ast_pbx_start(chan)) {
05156 ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05157 if (channel) {
05158 *channel = NULL;
05159 ast_channel_unlock(chan);
05160 }
05161 ast_hangup(chan);
05162 res = -1;
05163 }
05164 chan = NULL;
05165 }
05166 } else {
05167 if (option_verbose > 3)
05168 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05169
05170 if (chan->cdr) {
05171
05172
05173 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05174 ast_cdr_failed(chan->cdr);
05175 }
05176
05177 if (channel) {
05178 *channel = NULL;
05179 ast_channel_unlock(chan);
05180 }
05181 ast_hangup(chan);
05182 chan = NULL;
05183 }
05184 }
05185
05186 if (res < 0) {
05187 if (*reason == 0) {
05188
05189 cdr_res = ast_pbx_outgoing_cdr_failed();
05190 if (cdr_res != 0) {
05191 res = cdr_res;
05192 goto outgoing_exten_cleanup;
05193 }
05194 }
05195
05196
05197
05198 if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05199 chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
05200 if (chan) {
05201 char failed_reason[4] = "";
05202 if (!ast_strlen_zero(context))
05203 ast_copy_string(chan->context, context, sizeof(chan->context));
05204 set_ext_pri(chan, "failed", 1);
05205 ast_set_variables(chan, vars);
05206 snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
05207 pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
05208 if (account)
05209 ast_cdr_setaccount(chan, account);
05210 if (ast_pbx_run(chan)) {
05211 ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05212 ast_hangup(chan);
05213 }
05214 chan = NULL;
05215 }
05216 }
05217 }
05218 } else {
05219 if (!(as = ast_calloc(1, sizeof(*as)))) {
05220 res = -1;
05221 goto outgoing_exten_cleanup;
05222 }
05223 chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05224 if (channel) {
05225 *channel = chan;
05226 if (chan)
05227 ast_channel_lock(chan);
05228 }
05229 if (!chan) {
05230 free(as);
05231 res = -1;
05232 goto outgoing_exten_cleanup;
05233 }
05234 as->chan = chan;
05235 ast_copy_string(as->context, context, sizeof(as->context));
05236 set_ext_pri(as->chan, exten, priority);
05237 as->timeout = timeout;
05238 ast_set_variables(chan, vars);
05239 if (account)
05240 ast_cdr_setaccount(chan, account);
05241 pthread_attr_init(&attr);
05242 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05243 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05244 ast_log(LOG_WARNING, "Failed to start async wait\n");
05245 free(as);
05246 if (channel) {
05247 *channel = NULL;
05248 ast_channel_unlock(chan);
05249 }
05250 ast_hangup(chan);
05251 res = -1;
05252 pthread_attr_destroy(&attr);
05253 goto outgoing_exten_cleanup;
05254 }
05255 pthread_attr_destroy(&attr);
05256 res = 0;
05257 }
05258 outgoing_exten_cleanup:
05259 ast_variables_destroy(vars);
05260 return res;
05261 }
05262
05263 struct app_tmp {
05264 char app[256];
05265 char data[256];
05266 struct ast_channel *chan;
05267 pthread_t t;
05268 };
05269
05270
05271 static void *ast_pbx_run_app(void *data)
05272 {
05273 struct app_tmp *tmp = data;
05274 struct ast_app *app;
05275 app = pbx_findapp(tmp->app);
05276 if (app) {
05277 if (option_verbose > 3)
05278 ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05279 pbx_exec(tmp->chan, app, tmp->data);
05280 } else
05281 ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05282 ast_hangup(tmp->chan);
05283 free(tmp);
05284 return NULL;
05285 }
05286
05287 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)
05288 {
05289 struct ast_channel *chan;
05290 struct app_tmp *tmp;
05291 int res = -1, cdr_res = -1;
05292 struct outgoing_helper oh;
05293 pthread_attr_t attr;
05294
05295 memset(&oh, 0, sizeof(oh));
05296 oh.vars = vars;
05297 oh.account = account;
05298
05299 if (locked_channel)
05300 *locked_channel = NULL;
05301 if (ast_strlen_zero(app)) {
05302 res = -1;
05303 goto outgoing_app_cleanup;
05304 }
05305 if (sync) {
05306 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05307 if (chan) {
05308 ast_set_variables(chan, vars);
05309 if (account)
05310 ast_cdr_setaccount(chan, account);
05311 if (chan->_state == AST_STATE_UP) {
05312 res = 0;
05313 if (option_verbose > 3)
05314 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05315 tmp = ast_calloc(1, sizeof(*tmp));
05316 if (!tmp)
05317 res = -1;
05318 else {
05319 ast_copy_string(tmp->app, app, sizeof(tmp->app));
05320 if (appdata)
05321 ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05322 tmp->chan = chan;
05323 if (sync > 1) {
05324 if (locked_channel)
05325 ast_channel_unlock(chan);
05326 ast_pbx_run_app(tmp);
05327 } else {
05328 pthread_attr_init(&attr);
05329 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05330 if (locked_channel)
05331 ast_channel_lock(chan);
05332 if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05333 ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05334 free(tmp);
05335 if (locked_channel)
05336 ast_channel_unlock(chan);
05337 ast_hangup(chan);
05338 res = -1;
05339 } else {
05340 if (locked_channel)
05341 *locked_channel = chan;
05342 }
05343 pthread_attr_destroy(&attr);
05344 }
05345 }
05346 } else {
05347 if (option_verbose > 3)
05348 ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05349 if (chan->cdr) {
05350
05351
05352 if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05353 ast_cdr_failed(chan->cdr);
05354 }
05355 ast_hangup(chan);
05356 }
05357 }
05358
05359 if (res < 0) {
05360 if (*reason == 0) {
05361
05362 cdr_res = ast_pbx_outgoing_cdr_failed();
05363 if (cdr_res != 0) {
05364 res = cdr_res;
05365 goto outgoing_app_cleanup;
05366 }
05367 }
05368 }
05369
05370 } else {
05371 struct async_stat *as;
05372 if (!(as = ast_calloc(1, sizeof(*as)))) {
05373 res = -1;
05374 goto outgoing_app_cleanup;
05375 }
05376 chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05377 if (!chan) {
05378 free(as);
05379 res = -1;
05380 goto outgoing_app_cleanup;
05381 }
05382 as->chan = chan;
05383 ast_copy_string(as->app, app, sizeof(as->app));
05384 if (appdata)
05385 ast_copy_string(as->appdata, appdata, sizeof(as->appdata));
05386 as->timeout = timeout;
05387 ast_set_variables(chan, vars);
05388 if (account)
05389 ast_cdr_setaccount(chan, account);
05390
05391 pthread_attr_init(&attr);
05392 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05393 if (locked_channel)
05394 ast_channel_lock(chan);
05395 if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05396 ast_log(LOG_WARNING, "Failed to start async wait\n");
05397 free(as);
05398 if (locked_channel)
05399 ast_channel_unlock(chan);
05400 ast_hangup(chan);
05401 res = -1;
05402 pthread_attr_destroy(&attr);
05403 goto outgoing_app_cleanup;
05404 } else {
05405 if (locked_channel)
05406 *locked_channel = chan;
05407 }
05408 pthread_attr_destroy(&attr);
05409 res = 0;
05410 }
05411 outgoing_app_cleanup:
05412 ast_variables_destroy(vars);
05413 return res;
05414 }
05415
05416 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05417 {
05418 struct ast_context *tmp, *tmpl=NULL;
05419 struct ast_include *tmpi;
05420 struct ast_sw *sw;
05421 struct ast_exten *e, *el, *en;
05422 struct ast_ignorepat *ipi;
05423
05424 for (tmp = contexts; tmp; ) {
05425 struct ast_context *next;
05426 for (; tmp; tmpl = tmp, tmp = tmp->next) {
05427 if (option_debug)
05428 ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
05429 if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
05430 (!con || !strcasecmp(tmp->name, con->name)) )
05431 break;
05432 }
05433 if (!tmp)
05434 break;
05435 ast_mutex_lock(&tmp->lock);
05436 if (option_debug)
05437 ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
05438 next = tmp->next;
05439 if (tmpl)
05440 tmpl->next = next;
05441 else
05442 contexts = next;
05443
05444
05445 ast_mutex_unlock(&tmp->lock);
05446 for (tmpi = tmp->includes; tmpi; ) {
05447 struct ast_include *tmpil = tmpi;
05448 tmpi = tmpi->next;
05449 free(tmpil);
05450 }
05451 for (ipi = tmp->ignorepats; ipi; ) {
05452 struct ast_ignorepat *ipl = ipi;
05453 ipi = ipi->next;
05454 free(ipl);
05455 }
05456 while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
05457 free(sw);
05458 for (e = tmp->root; e;) {
05459 for (en = e->peer; en;) {
05460 el = en;
05461 en = en->peer;
05462 destroy_exten(el);
05463 }
05464 el = e;
05465 e = e->next;
05466 destroy_exten(el);
05467 }
05468 ast_mutex_destroy(&tmp->lock);
05469 free(tmp);
05470
05471 tmp = con ? NULL : next;
05472 }
05473 }
05474
05475 void ast_context_destroy(struct ast_context *con, const char *registrar)
05476 {
05477 ast_wrlock_contexts();
05478 __ast_context_destroy(con,registrar);
05479 ast_unlock_contexts();
05480 }
05481
05482 static void wait_for_hangup(struct ast_channel *chan, void *data)
05483 {
05484 int res;
05485 struct ast_frame *f;
05486 int waittime;
05487
05488 if (ast_strlen_zero(data) || (sscanf(data, "%30d", &waittime) != 1) || (waittime < 0))
05489 waittime = -1;
05490 if (waittime > -1) {
05491 ast_safe_sleep(chan, waittime * 1000);
05492 } else do {
05493 res = ast_waitfor(chan, -1);
05494 if (res < 0)
05495 return;
05496 f = ast_read(chan);
05497 if (f)
05498 ast_frfree(f);
05499 } while(f);
05500 }
05501
05502
05503
05504
05505 static int pbx_builtin_proceeding(struct ast_channel *chan, void *data)
05506 {
05507 ast_indicate(chan, AST_CONTROL_PROCEEDING);
05508 return 0;
05509 }
05510
05511
05512
05513
05514 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05515 {
05516 ast_indicate(chan, AST_CONTROL_PROGRESS);
05517 return 0;
05518 }
05519
05520
05521
05522
05523 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05524 {
05525 ast_indicate(chan, AST_CONTROL_RINGING);
05526 return 0;
05527 }
05528
05529
05530
05531
05532 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05533 {
05534 ast_indicate(chan, AST_CONTROL_BUSY);
05535
05536
05537 if (chan->_state != AST_STATE_UP) {
05538 ast_setstate(chan, AST_STATE_BUSY);
05539 ast_cdr_busy(chan->cdr);
05540 }
05541 wait_for_hangup(chan, data);
05542 return -1;
05543 }
05544
05545
05546
05547
05548 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
05549 {
05550 ast_indicate(chan, AST_CONTROL_CONGESTION);
05551
05552
05553 if (chan->_state != AST_STATE_UP)
05554 ast_setstate(chan, AST_STATE_BUSY);
05555 wait_for_hangup(chan, data);
05556 return -1;
05557 }
05558
05559
05560
05561
05562 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05563 {
05564 int delay = 0;
05565 int res;
05566
05567 if (chan->_state == AST_STATE_UP)
05568 delay = 0;
05569 else if (!ast_strlen_zero(data))
05570 delay = atoi(data);
05571
05572 res = ast_answer(chan);
05573 if (res)
05574 return res;
05575
05576 if (delay)
05577 res = ast_safe_sleep(chan, delay);
05578
05579 return res;
05580 }
05581
05582 AST_APP_OPTIONS(resetcdr_opts, {
05583 AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05584 AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05585 AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05586 });
05587
05588
05589
05590
05591 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05592 {
05593 char *args;
05594 struct ast_flags flags = { 0 };
05595
05596 if (!ast_strlen_zero(data)) {
05597 args = ast_strdupa(data);
05598 ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05599 }
05600
05601 ast_cdr_reset(chan->cdr, &flags);
05602
05603 return 0;
05604 }
05605
05606
05607
05608
05609 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05610 {
05611
05612 ast_cdr_setamaflags(chan, data ? data : "");
05613 return 0;
05614 }
05615
05616
05617
05618
05619 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05620 {
05621 if (!ast_strlen_zero(data)) {
05622 int cause;
05623 char *endptr;
05624
05625 if ((cause = ast_str2cause(data)) > -1) {
05626 chan->hangupcause = cause;
05627 return -1;
05628 }
05629
05630 cause = strtol((const char *) data, &endptr, 10);
05631 if (cause != 0 || (data != endptr)) {
05632 chan->hangupcause = cause;
05633 return -1;
05634 }
05635
05636 ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
05637 }
05638
05639 if (!chan->hangupcause) {
05640 chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05641 }
05642
05643 return -1;
05644 }
05645
05646
05647
05648
05649 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05650 {
05651 int res=0;
05652 char *s, *ts;
05653 struct ast_timing timing;
05654
05655 if (ast_strlen_zero(data)) {
05656 ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05657 return -1;
05658 }
05659
05660 ts = s = ast_strdupa(data);
05661
05662
05663 strsep(&ts,"?");
05664
05665
05666 if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05667 res = pbx_builtin_goto(chan, ts);
05668
05669 return res;
05670 }
05671
05672
05673
05674
05675 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05676 {
05677 char *s, *appname;
05678 struct ast_timing timing;
05679 struct ast_app *app;
05680 static const char *usage = "ExecIfTime requires an argument:\n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05681
05682 if (ast_strlen_zero(data)) {
05683 ast_log(LOG_WARNING, "%s\n", usage);
05684 return -1;
05685 }
05686
05687 appname = ast_strdupa(data);
05688
05689 s = strsep(&appname,"?");
05690 if (!appname) {
05691 ast_log(LOG_WARNING, "%s\n", usage);
05692 return -1;
05693 }
05694
05695 if (!ast_build_timing(&timing, s)) {
05696 ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
05697 return -1;
05698 }
05699
05700 if (!ast_check_timing(&timing))
05701 return 0;
05702
05703
05704 if ((s = strchr(appname, '|')))
05705 *s++ = '\0';
05706
05707 if ((app = pbx_findapp(appname))) {
05708 return pbx_exec(chan, app, S_OR(s, ""));
05709 } else {
05710 ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
05711 return -1;
05712 }
05713 }
05714
05715
05716
05717
05718 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05719 {
05720 double s;
05721 int ms;
05722
05723
05724 if (data && (s = atof(data)) > 0) {
05725 ms = s * 1000.0;
05726 return ast_safe_sleep(chan, ms);
05727 }
05728 return 0;
05729 }
05730
05731
05732
05733
05734 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05735 {
05736 int ms, res;
05737 double sec;
05738 struct ast_flags flags = {0};
05739 char *opts[1] = { NULL };
05740 char *parse;
05741 AST_DECLARE_APP_ARGS(args,
05742 AST_APP_ARG(timeout);
05743 AST_APP_ARG(options);
05744 );
05745
05746 if (!ast_strlen_zero(data)) {
05747 parse = ast_strdupa(data);
05748 AST_STANDARD_APP_ARGS(args, parse);
05749 } else
05750 memset(&args, 0, sizeof(args));
05751
05752 if (args.options)
05753 ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
05754
05755 if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
05756 ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n");
05757 } else if (ast_test_flag(&flags, WAITEXTEN_MOH))
05758 ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL), strlen(opts[0]));
05759
05760
05761 if (args.timeout && (sec = atof(args.timeout)) > 0.0)
05762 ms = 1000 * sec;
05763 else if (chan->pbx)
05764 ms = chan->pbx->rtimeout * 1000;
05765 else
05766 ms = 10000;
05767 res = ast_waitfordigit(chan, ms);
05768 if (!res) {
05769 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05770 if (option_verbose > 2)
05771 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05772 } else if (chan->_softhangup & AST_SOFTHANGUP_TIMEOUT) {
05773 if (option_verbose > 2)
05774 ast_verbose(VERBOSE_PREFIX_3 "Call timeout on %s, checking for 'T'\n", chan->name);
05775 res = -1;
05776 } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05777 if (option_verbose > 2)
05778 ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05779 set_ext_pri(chan, "t", 0);
05780 } else {
05781 ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05782 res = -1;
05783 }
05784 }
05785
05786 if (ast_test_flag(&flags, WAITEXTEN_MOH))
05787 ast_indicate(chan, AST_CONTROL_UNHOLD);
05788
05789 return res;
05790 }
05791
05792
05793
05794
05795 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05796 {
05797 int res = 0;
05798 struct ast_flags flags = {0};
05799 char *parse, exten[2] = "";
05800 AST_DECLARE_APP_ARGS(args,
05801 AST_APP_ARG(filename);
05802 AST_APP_ARG(options);
05803 AST_APP_ARG(lang);
05804 AST_APP_ARG(context);
05805 );
05806
05807 if (ast_strlen_zero(data)) {
05808 ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05809 return -1;
05810 }
05811
05812 parse = ast_strdupa(data);
05813
05814 AST_STANDARD_APP_ARGS(args, parse);
05815
05816 if (ast_strlen_zero(args.lang))
05817 args.lang = (char *)chan->language;
05818
05819 if (ast_strlen_zero(args.context)) {
05820 const char *context;
05821 ast_channel_lock(chan);
05822 if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
05823 args.context = ast_strdupa(context);
05824 } else {
05825 args.context = chan->context;
05826 }
05827 ast_channel_unlock(chan);
05828 }
05829
05830 if (args.options) {
05831 if (!strcasecmp(args.options, "skip"))
05832 flags.flags = BACKGROUND_SKIP;
05833 else if (!strcasecmp(args.options, "noanswer"))
05834 flags.flags = BACKGROUND_NOANSWER;
05835 else
05836 ast_app_parse_options(background_opts, &flags, NULL, args.options);
05837 }
05838
05839
05840 if (chan->_state != AST_STATE_UP) {
05841 if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05842 return 0;
05843 } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05844 res = ast_answer(chan);
05845 }
05846 }
05847
05848 if (!res) {
05849 char *back = args.filename;
05850 char *front;
05851 ast_stopstream(chan);
05852
05853 while (!res && (front = strsep(&back, "&")) ) {
05854 if ( (res = ast_streamfile(chan, front, args.lang)) ) {
05855 ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05856 res = 0;
05857 break;
05858 }
05859 if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05860 res = ast_waitstream(chan, "");
05861 } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05862 res = ast_waitstream_exten(chan, args.context);
05863 } else {
05864 res = ast_waitstream(chan, AST_DIGIT_ANY);
05865 }
05866 ast_stopstream(chan);
05867 }
05868 }
05869
05870
05871
05872
05873
05874
05875
05876
05877
05878
05879
05880
05881
05882
05883
05884
05885
05886
05887
05888 if (!ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS) &&
05889 (exten[0] = res) &&
05890 ast_canmatch_extension(chan, args.context, exten, 1, chan->cid.cid_num) &&
05891 !ast_matchmore_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
05892 snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05893 ast_copy_string(chan->context, args.context, sizeof(chan->context));
05894 chan->priority = 0;
05895 res = 0;
05896 }
05897 return res;
05898 }
05899
05900
05901
05902
05903 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05904 {
05905 int res = ast_parseable_goto(chan, data);
05906 if (!res && (option_verbose > 2))
05907 ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05908 return res;
05909 }
05910
05911
05912 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05913 {
05914 struct ast_var_t *variables;
05915 const char *var, *val;
05916 int total = 0;
05917
05918 if (!chan)
05919 return 0;
05920
05921 memset(buf, 0, size);
05922
05923 ast_channel_lock(chan);
05924
05925 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05926 if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
05927
05928 ) {
05929 if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05930 ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05931 break;
05932 } else
05933 total++;
05934 } else
05935 break;
05936 }
05937
05938 ast_channel_unlock(chan);
05939
05940 return total;
05941 }
05942
05943 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05944 {
05945 struct ast_var_t *variables;
05946 const char *ret = NULL;
05947 int i;
05948 struct varshead *places[2] = { NULL, &globals };
05949
05950 if (!name)
05951 return NULL;
05952
05953 if (chan) {
05954 ast_channel_lock(chan);
05955 places[0] = &chan->varshead;
05956 }
05957
05958 for (i = 0; i < 2; i++) {
05959 if (!places[i])
05960 continue;
05961 if (places[i] == &globals)
05962 ast_mutex_lock(&globalslock);
05963 AST_LIST_TRAVERSE(places[i], variables, entries) {
05964 if (!strcmp(name, ast_var_name(variables))) {
05965 ret = ast_var_value(variables);
05966 break;
05967 }
05968 }
05969 if (places[i] == &globals)
05970 ast_mutex_unlock(&globalslock);
05971 if (ret)
05972 break;
05973 }
05974
05975 if (chan)
05976 ast_channel_unlock(chan);
05977
05978 return ret;
05979 }
05980
05981 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05982 {
05983 struct ast_var_t *newvariable;
05984 struct varshead *headp;
05985
05986 if (name[strlen(name)-1] == ')') {
05987 char *function = ast_strdupa(name);
05988
05989 ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05990 ast_func_write(chan, function, value);
05991 return;
05992 }
05993
05994 if (chan) {
05995 ast_channel_lock(chan);
05996 headp = &chan->varshead;
05997 } else {
05998 ast_mutex_lock(&globalslock);
05999 headp = &globals;
06000 }
06001
06002 if (value) {
06003 if ((option_verbose > 1) && (headp == &globals))
06004 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
06005 newvariable = ast_var_assign(name, value);
06006 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
06007 }
06008
06009 if (chan)
06010 ast_channel_unlock(chan);
06011 else
06012 ast_mutex_unlock(&globalslock);
06013 }
06014
06015 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
06016 {
06017 struct ast_var_t *newvariable;
06018 struct varshead *headp;
06019 const char *nametail = name;
06020
06021 if (name[strlen(name)-1] == ')') {
06022 char *function = ast_strdupa(name);
06023
06024 ast_func_write(chan, function, value);
06025 return;
06026 }
06027
06028 if (chan) {
06029 ast_channel_lock(chan);
06030 headp = &chan->varshead;
06031 } else {
06032 ast_mutex_lock(&globalslock);
06033 headp = &globals;
06034 }
06035
06036
06037 if (*nametail == '_') {
06038 nametail++;
06039 if (*nametail == '_')
06040 nametail++;
06041 }
06042
06043 AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
06044 if (strcmp(ast_var_name(newvariable), nametail) == 0) {
06045
06046 AST_LIST_REMOVE_CURRENT(headp, entries);
06047 ast_var_delete(newvariable);
06048 break;
06049 }
06050 }
06051 AST_LIST_TRAVERSE_SAFE_END;
06052
06053 if (value) {
06054 if ((option_verbose > 1) && (headp == &globals))
06055 ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
06056 newvariable = ast_var_assign(name, value);
06057 AST_LIST_INSERT_HEAD(headp, newvariable, entries);
06058 }
06059
06060 if (chan)
06061 ast_channel_unlock(chan);
06062 else
06063 ast_mutex_unlock(&globalslock);
06064 }
06065
06066 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
06067 {
06068 char *name, *value, *mydata;
06069 int argc;
06070 char *argv[24];
06071 int global = 0;
06072 int x;
06073
06074 if (ast_strlen_zero(data)) {
06075 ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
06076 return 0;
06077 }
06078
06079 mydata = ast_strdupa(data);
06080 argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
06081
06082
06083 if ((argc > 1) && !strchr(argv[argc-1], '=')) {
06084 argc--;
06085 if (strchr(argv[argc], 'g')) {
06086 ast_log(LOG_WARNING, "The use of the 'g' flag is deprecated. Please use Set(GLOBAL(foo)=bar) instead\n");
06087 global = 1;
06088 }
06089 }
06090
06091 if (argc > 1)
06092 ast_log(LOG_WARNING, "Setting multiple variables at once within Set is deprecated. Please separate each name/value pair into its own line.\n");
06093
06094 for (x = 0; x < argc; x++) {
06095 name = argv[x];
06096 if ((value = strchr(name, '='))) {
06097 *value++ = '\0';
06098 pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
06099 } else
06100 ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
06101 }
06102
06103 return(0);
06104 }
06105
06106 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
06107 {
06108 char *name;
06109 char *value;
06110 char *channel;
06111 char tmp[VAR_BUF_SIZE]="";
06112
06113 if (ast_strlen_zero(data)) {
06114 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06115 return 0;
06116 }
06117
06118 value = ast_strdupa(data);
06119 name = strsep(&value,"=");
06120 channel = strsep(&value,"|");
06121 if (channel && value && name) {
06122 struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
06123 if (chan2) {
06124 char *s = alloca(strlen(value) + 4);
06125 if (s) {
06126 sprintf(s, "${%s}", value);
06127 pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
06128 }
06129 ast_channel_unlock(chan2);
06130 }
06131 pbx_builtin_setvar_helper(chan, name, tmp);
06132 }
06133
06134 return(0);
06135 }
06136
06137
06138 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
06139 {
06140 char *name;
06141 char *stringp = data;
06142 static int dep_warning = 0;
06143
06144 if (ast_strlen_zero(data)) {
06145 ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06146 return 0;
06147 }
06148
06149 name = strsep(&stringp, "=");
06150
06151 if (!dep_warning) {
06152 dep_warning = 1;
06153 ast_log(LOG_WARNING, "SetGlobalVar is deprecated. Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
06154 }
06155
06156
06157 pbx_builtin_setvar_helper(NULL, name, stringp);
06158
06159 return(0);
06160 }
06161
06162 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
06163 {
06164 return 0;
06165 }
06166
06167 void pbx_builtin_clear_globals(void)
06168 {
06169 struct ast_var_t *vardata;
06170
06171 ast_mutex_lock(&globalslock);
06172 while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
06173 ast_var_delete(vardata);
06174 ast_mutex_unlock(&globalslock);
06175 }
06176
06177 int pbx_checkcondition(const char *condition)
06178 {
06179 if (ast_strlen_zero(condition))
06180 return 0;
06181 else if (*condition >= '0' && *condition <= '9')
06182 return atoi(condition);
06183 else
06184 return 1;
06185 }
06186
06187 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
06188 {
06189 char *condition, *branch1, *branch2, *branch;
06190 int rc;
06191 char *stringp;
06192
06193 if (ast_strlen_zero(data)) {
06194 ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
06195 return 0;
06196 }
06197
06198 stringp = ast_strdupa(data);
06199 condition = strsep(&stringp,"?");
06200 branch1 = strsep(&stringp,":");
06201 branch2 = strsep(&stringp,"");
06202 branch = pbx_checkcondition(condition) ? branch1 : branch2;
06203
06204 if (ast_strlen_zero(branch)) {
06205 if (option_debug)
06206 ast_log(LOG_DEBUG, "Not taking any branch\n");
06207 return 0;
06208 }
06209
06210 rc = pbx_builtin_goto(chan, branch);
06211
06212 return rc;
06213 }
06214
06215 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
06216 {
06217 char tmp[256];
06218 char *number = tmp;
06219 char *options;
06220
06221 if (ast_strlen_zero(data)) {
06222 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06223 return -1;
06224 }
06225 ast_copy_string(tmp, data, sizeof(tmp));
06226 strsep(&number, "|");
06227 options = strsep(&number, "|");
06228 if (options) {
06229 if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06230 strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06231 ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06232 return -1;
06233 }
06234 }
06235
06236 if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
06237 ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
06238 }
06239
06240 return 0;
06241 }
06242
06243 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06244 {
06245 int res = 0;
06246
06247 if (data)
06248 res = ast_say_digit_str(chan, data, "", chan->language);
06249 return res;
06250 }
06251
06252 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06253 {
06254 int res = 0;
06255
06256 if (data)
06257 res = ast_say_character_str(chan, data, "", chan->language);
06258 return res;
06259 }
06260
06261 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06262 {
06263 int res = 0;
06264
06265 if (data)
06266 res = ast_say_phonetic_str(chan, data, "", chan->language);
06267 return res;
06268 }
06269
06270 static int pbx_builtin_saydate(struct ast_channel *chan, void *data)
06271 {
06272 int res = 0;
06273 char *parse;
06274 int unixdate = 0;
06275 char charascii[2];
06276
06277 AST_DECLARE_APP_ARGS(args,
06278 AST_APP_ARG(datestr);
06279 AST_APP_ARG(digits);
06280 );
06281
06282
06283 if (ast_strlen_zero(data)) {
06284 ast_log(LOG_WARNING, "SayDate requires an argument (date)\n");
06285 return -1;
06286 }
06287
06288 if (!(parse = ast_strdupa(data))) {
06289 ast_log(LOG_WARNING, "Memory Error!\n");
06290 return -1;
06291 }
06292
06293 AST_STANDARD_APP_ARGS(args, parse);
06294
06295 if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
06296 ast_log(LOG_WARNING, "SayDate escape digits must be a subset from '0123456789*#'\n");
06297 args.digits = "";
06298 }
06299
06300 if (sscanf(args.datestr, "%d", &unixdate) != 1) {
06301 ast_log(LOG_WARNING, "Firt argument to SayDate must be numeric (date)\n");
06302 return -1;
06303 }
06304
06305 res = ast_say_date(chan, (time_t)unixdate, args.digits, chan->language);
06306 if (res > 0) {
06307 if (isdigit(res) || (res == '*') || (res == '#')) {
06308 snprintf(charascii, 2, "%c", res);
06309 pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
06310 res = 0;
06311 } else {
06312 ast_log(LOG_WARNING, "SayDate: invalid return value (%d) detected\n", res);
06313 }
06314 }
06315 return res;
06316 }
06317
06318 static int pbx_builtin_saytime(struct ast_channel *chan, void *data)
06319 {
06320 int res = 0;
06321 char *parse;
06322 int secs = 0;
06323 char charascii[2];
06324
06325 AST_DECLARE_APP_ARGS(args,
06326 AST_APP_ARG(timestr);
06327 AST_APP_ARG(digits);
06328 );
06329
06330 if (ast_strlen_zero(data)) {
06331 ast_log(LOG_WARNING, "SayTime requires an argument (time in seconds)\n");
06332 return -1;
06333 }
06334
06335 if (!(parse = ast_strdupa(data))) {
06336 ast_log(LOG_WARNING, "Memory Error!\n");
06337 return -1;
06338 }
06339
06340 AST_STANDARD_APP_ARGS(args, parse);
06341
06342 if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
06343 ast_log(LOG_WARNING, "SayTime escape digits must be a subset from '0123456789*#'\n");
06344 args.digits = "";
06345 }
06346
06347 if (sscanf(args.timestr, "%d", &secs) != 1) {
06348 ast_log(LOG_WARNING, "Firt argument to SayTime must be numeric (time in seconds)\n");
06349 return -1;
06350 }
06351
06352 res = ast_say_time(chan, (time_t)secs, args.digits, chan->language);
06353 if (res > 0) {
06354 if (isdigit(res) || (res == '*') || (res == '#')) {
06355 snprintf(charascii, 2, "%c", res);
06356 pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
06357 res = 0;
06358 } else {
06359 ast_log(LOG_WARNING, "SayTime: invalid return value (%d) detected\n", res);
06360 }
06361 }
06362 return res;
06363 }
06364
06365 int load_pbx(void)
06366 {
06367 int x;
06368
06369
06370 if (option_verbose) {
06371 ast_verbose( "Asterisk PBX Core Initializing\n");
06372 ast_verbose( "Registering builtin applications:\n");
06373 }
06374 ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
06375
06376
06377 for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06378 if (option_verbose)
06379 ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06380 if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06381 ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06382 return -1;
06383 }
06384 }
06385 return 0;
06386 }
06387
06388
06389
06390
06391 int ast_lock_contexts()
06392 {
06393 return ast_mutex_lock(&conlock);
06394 }
06395
06396 int ast_rdlock_contexts(void)
06397 {
06398 return ast_mutex_lock(&conlock);
06399 }
06400
06401 int ast_wrlock_contexts(void)
06402 {
06403 return ast_mutex_lock(&conlock);
06404 }
06405
06406 int ast_unlock_contexts()
06407 {
06408 return ast_mutex_unlock(&conlock);
06409 }
06410
06411
06412
06413
06414 int ast_lock_context(struct ast_context *con)
06415 {
06416 return ast_mutex_lock(&con->lock);
06417 }
06418
06419 int ast_unlock_context(struct ast_context *con)
06420 {
06421 return ast_mutex_unlock(&con->lock);
06422 }
06423
06424
06425
06426
06427 const char *ast_get_context_name(struct ast_context *con)
06428 {
06429 return con ? con->name : NULL;
06430 }
06431
06432 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
06433 {
06434 return exten ? exten->parent : NULL;
06435 }
06436
06437 const char *ast_get_extension_name(struct ast_exten *exten)
06438 {
06439 return exten ? exten->exten : NULL;
06440 }
06441
06442 const char *ast_get_extension_label(struct ast_exten *exten)
06443 {
06444 return exten ? exten->label : NULL;
06445 }
06446
06447 const char *ast_get_include_name(struct ast_include *inc)
06448 {
06449 return inc ? inc->name : NULL;
06450 }
06451
06452 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06453 {
06454 return ip ? ip->pattern : NULL;
06455 }
06456
06457 int ast_get_extension_priority(struct ast_exten *exten)
06458 {
06459 return exten ? exten->priority : -1;
06460 }
06461
06462
06463
06464
06465 const char *ast_get_context_registrar(struct ast_context *c)
06466 {
06467 return c ? c->registrar : NULL;
06468 }
06469
06470 const char *ast_get_extension_registrar(struct ast_exten *e)
06471 {
06472 return e ? e->registrar : NULL;
06473 }
06474
06475 const char *ast_get_include_registrar(struct ast_include *i)
06476 {
06477 return i ? i->registrar : NULL;
06478 }
06479
06480 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06481 {
06482 return ip ? ip->registrar : NULL;
06483 }
06484
06485 int ast_get_extension_matchcid(struct ast_exten *e)
06486 {
06487 return e ? e->matchcid : 0;
06488 }
06489
06490 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06491 {
06492 return e ? e->cidmatch : NULL;
06493 }
06494
06495 const char *ast_get_extension_app(struct ast_exten *e)
06496 {
06497 return e ? e->app : NULL;
06498 }
06499
06500 void *ast_get_extension_app_data(struct ast_exten *e)
06501 {
06502 return e ? e->data : NULL;
06503 }
06504
06505 const char *ast_get_switch_name(struct ast_sw *sw)
06506 {
06507 return sw ? sw->name : NULL;
06508 }
06509
06510 const char *ast_get_switch_data(struct ast_sw *sw)
06511 {
06512 return sw ? sw->data : NULL;
06513 }
06514
06515 const char *ast_get_switch_registrar(struct ast_sw *sw)
06516 {
06517 return sw ? sw->registrar : NULL;
06518 }
06519
06520
06521
06522
06523 struct ast_context *ast_walk_contexts(struct ast_context *con)
06524 {
06525 return con ? con->next : contexts;
06526 }
06527
06528 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06529 struct ast_exten *exten)
06530 {
06531 if (!exten)
06532 return con ? con->root : NULL;
06533 else
06534 return exten->next;
06535 }
06536
06537 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06538 struct ast_sw *sw)
06539 {
06540 if (!sw)
06541 return con ? AST_LIST_FIRST(&con->alts) : NULL;
06542 else
06543 return AST_LIST_NEXT(sw, list);
06544 }
06545
06546 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06547 struct ast_exten *priority)
06548 {
06549 return priority ? priority->peer : exten;
06550 }
06551
06552 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06553 struct ast_include *inc)
06554 {
06555 if (!inc)
06556 return con ? con->includes : NULL;
06557 else
06558 return inc->next;
06559 }
06560
06561 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06562 struct ast_ignorepat *ip)
06563 {
06564 if (!ip)
06565 return con ? con->ignorepats : NULL;
06566 else
06567 return ip->next;
06568 }
06569
06570 int ast_context_verify_includes(struct ast_context *con)
06571 {
06572 struct ast_include *inc = NULL;
06573 int res = 0;
06574
06575 while ( (inc = ast_walk_context_includes(con, inc)) ) {
06576 if (ast_context_find(inc->rname))
06577 continue;
06578
06579 res = -1;
06580 ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
06581 ast_get_context_name(con), inc->rname);
06582 break;
06583 }
06584
06585 return res;
06586 }
06587
06588
06589 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
06590 {
06591 int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06592
06593 if (!chan)
06594 return -2;
06595
06596 if (context == NULL)
06597 context = chan->context;
06598 if (exten == NULL)
06599 exten = chan->exten;
06600
06601 goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06602 if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
06603 return goto_func(chan, context, exten, priority);
06604 else
06605 return -3;
06606 }
06607
06608 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
06609 {
06610 return __ast_goto_if_exists(chan, context, exten, priority, 0);
06611 }
06612
06613 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
06614 {
06615 return __ast_goto_if_exists(chan, context, exten, priority, 1);
06616 }
06617
06618 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06619 {
06620 char *exten, *pri, *context;
06621 char *stringp;
06622 int ipri;
06623 int mode = 0;
06624
06625 if (ast_strlen_zero(goto_string)) {
06626 ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06627 return -1;
06628 }
06629 stringp = ast_strdupa(goto_string);
06630 context = strsep(&stringp, "|");
06631 exten = strsep(&stringp, "|");
06632 pri = strsep(&stringp, "|");
06633 if (!exten) {
06634 pri = context;
06635 exten = NULL;
06636 context = NULL;
06637 } else if (!pri) {
06638 pri = exten;
06639 exten = context;
06640 context = NULL;
06641 }
06642 if (*pri == '+') {
06643 mode = 1;
06644 pri++;
06645 } else if (*pri == '-') {
06646 mode = -1;
06647 pri++;
06648 }
06649 if (sscanf(pri, "%30d", &ipri) != 1) {
06650 if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
06651 pri, chan->cid.cid_num)) < 1) {
06652 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06653 return -1;
06654 } else
06655 mode = 0;
06656 }
06657
06658
06659 if (mode)
06660 ipri = chan->priority + (ipri * mode);
06661
06662 ast_explicit_goto(chan, context, exten, ipri);
06663 return 0;
06664
06665 }
06666
06667 static int hint_hash(const void *hint, const int flags)
06668 {
06669
06670 return 0;
06671 }
06672
06673 static int hint_cmp(void *obj, void *arg, int flags)
06674 {
06675 const struct ast_hint *hint = obj;
06676 const struct ast_exten *exten = arg;
06677
06678 return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
06679 }
06680
06681 int ast_pbx_init(void)
06682 {
06683 hints = ao2_container_alloc(1, hint_hash, hint_cmp);
06684
06685 return hints ? 0 : -1;
06686 }