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: 144758 $")
00029
00030 #include <sys/types.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <ctype.h>
00036 #include <errno.h>
00037 #include <time.h>
00038 #include <sys/time.h>
00039 #include <limits.h>
00040
00041 #include "asterisk/lock.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/file.h"
00048 #include "asterisk/callerid.h"
00049 #include "asterisk/cdr.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/term.h"
00052 #include "asterisk/manager.h"
00053 #include "asterisk/ast_expr.h"
00054 #include "asterisk/linkedlists.h"
00055 #define SAY_STUBS
00056 #include "asterisk/say.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/causes.h"
00059 #include "asterisk/musiconhold.h"
00060 #include "asterisk/app.h"
00061 #include "asterisk/devicestate.h"
00062 #include "asterisk/stringfields.h"
00063 #include "asterisk/threadstorage.h"
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 #ifdef LOW_MEMORY
00076 #define EXT_DATA_SIZE 256
00077 #else
00078 #define EXT_DATA_SIZE 8192
00079 #endif
00080
00081 #define SWITCH_DATA_LENGTH 256
00082
00083 #define VAR_BUF_SIZE 4096
00084
00085 #define VAR_NORMAL 1
00086 #define VAR_SOFTTRAN 2
00087 #define VAR_HARDTRAN 3
00088
00089 #define BACKGROUND_SKIP (1 << 0)
00090 #define BACKGROUND_NOANSWER (1 << 1)
00091 #define BACKGROUND_MATCHEXTEN (1 << 2)
00092 #define BACKGROUND_PLAYBACK (1 << 3)
00093
00094 AST_APP_OPTIONS(background_opts, {
00095 AST_APP_OPTION('s', BACKGROUND_SKIP),
00096 AST_APP_OPTION('n', BACKGROUND_NOANSWER),
00097 AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
00098 AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
00099 });
00100
00101 #define WAITEXTEN_MOH (1 << 0)
00102
00103 AST_APP_OPTIONS(waitexten_opts, {
00104 AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
00105 });
00106
00107 struct ast_context;
00108
00109 AST_THREADSTORAGE(switch_data, switch_data_init);
00110
00111
00112
00113
00114
00115
00116
00117 struct ast_exten {
00118 char *exten;
00119 int matchcid;
00120 const char *cidmatch;
00121 int priority;
00122 const char *label;
00123 struct ast_context *parent;
00124 const char *app;
00125 void *data;
00126 void (*datad)(void *);
00127 struct ast_exten *peer;
00128 const char *registrar;
00129 struct ast_exten *next;
00130 char stuff[0];
00131 };
00132
00133
00134 struct ast_include {
00135 const char *name;
00136 const char *rname;
00137 const char *registrar;
00138 int hastime;
00139 struct ast_timing timing;
00140 struct ast_include *next;
00141 char stuff[0];
00142 };
00143
00144
00145 struct ast_sw {
00146 char *name;
00147 const char *registrar;
00148 char *data;
00149 int eval;
00150 AST_LIST_ENTRY(ast_sw) list;
00151 char stuff[0];
00152 };
00153
00154
00155 struct ast_ignorepat {
00156 const char *registrar;
00157 struct ast_ignorepat *next;
00158 const char pattern[0];
00159 };
00160
00161
00162 struct ast_context {
00163 ast_mutex_t lock;
00164 struct ast_exten *root;
00165 struct ast_context *next;
00166 struct ast_include *includes;
00167 struct ast_ignorepat *ignorepats;
00168 const char *registrar;
00169 AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
00170 ast_mutex_t macrolock;
00171 char name[0];
00172 };
00173
00174
00175
00176 struct ast_app {
00177 int (*execute)(struct ast_channel *chan, void *data);
00178 const char *synopsis;
00179 const char *description;
00180 AST_LIST_ENTRY(ast_app) list;
00181 struct module *module;
00182 char name[0];
00183 };
00184
00185
00186 struct ast_state_cb {
00187 int id;
00188 void *data;
00189 ast_state_cb_type callback;
00190 struct ast_state_cb *next;
00191 };
00192
00193
00194
00195
00196
00197 struct ast_hint {
00198 struct ast_exten *exten;
00199 int laststate;
00200 struct ast_state_cb *callbacks;
00201 AST_LIST_ENTRY(ast_hint) list;
00202 };
00203
00204 static const struct cfextension_states {
00205 int extension_state;
00206 const char * const text;
00207 } extension_states[] = {
00208 { AST_EXTENSION_NOT_INUSE, "Idle" },
00209 { AST_EXTENSION_INUSE, "InUse" },
00210 { AST_EXTENSION_BUSY, "Busy" },
00211 { AST_EXTENSION_UNAVAILABLE, "Unavailable" },
00212 { AST_EXTENSION_RINGING, "Ringing" },
00213 { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
00214 { AST_EXTENSION_ONHOLD, "Hold" },
00215 { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD, "InUse&Hold" }
00216 };
00217
00218 static int pbx_builtin_answer(struct ast_channel *, void *);
00219 static int pbx_builtin_goto(struct ast_channel *, void *);
00220 static int pbx_builtin_hangup(struct ast_channel *, void *);
00221 static int pbx_builtin_background(struct ast_channel *, void *);
00222 static int pbx_builtin_wait(struct ast_channel *, void *);
00223 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00224 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00225 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00226 static int pbx_builtin_ringing(struct ast_channel *, void *);
00227 static int pbx_builtin_progress(struct ast_channel *, void *);
00228 static int pbx_builtin_congestion(struct ast_channel *, void *);
00229 static int pbx_builtin_busy(struct ast_channel *, void *);
00230 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
00231 static int pbx_builtin_noop(struct ast_channel *, void *);
00232 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00233 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00234 static int pbx_builtin_execiftime(struct ast_channel *, void *);
00235 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00236 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00237 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00238 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00239 int pbx_builtin_setvar(struct ast_channel *, void *);
00240 static int pbx_builtin_importvar(struct ast_channel *, void *);
00241
00242 AST_MUTEX_DEFINE_STATIC(globalslock);
00243 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00244
00245 static int autofallthrough = 1;
00246
00247 AST_MUTEX_DEFINE_STATIC(maxcalllock);
00248 static int countcalls;
00249
00250 static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
00251
00252
00253 static struct pbx_builtin {
00254 char name[AST_MAX_APP];
00255 int (*execute)(struct ast_channel *chan, void *data);
00256 char *synopsis;
00257 char *description;
00258 } builtins[] =
00259 {
00260
00261
00262
00263 { "Answer", pbx_builtin_answer,
00264 "Answer a channel if ringing",
00265 " Answer([delay]): If the call has not been answered, this application will\n"
00266 "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
00267 "Asterisk will wait this number of milliseconds before returning to\n"
00268 "the dialplan after answering the call.\n"
00269 },
00270
00271 { "BackGround", pbx_builtin_background,
00272 "Play an audio file while waiting for digits of an extension to go to.",
00273 " Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
00274 "This application will play the given list of files (do not put extension)\n"
00275 "while waiting for an extension to be dialed by the calling channel. To\n"
00276 "continue waiting for digits after this application has finished playing\n"
00277 "files, the WaitExten application should be used. The 'langoverride' option\n"
00278 "explicitly specifies which language to attempt to use for the requested sound\n"
00279 "files. If a 'context' is specified, this is the dialplan context that this\n"
00280 "application will use when exiting to a dialed extension."
00281 " If one of the requested sound files does not exist, call processing will be\n"
00282 "terminated.\n"
00283 " Options:\n"
00284 " s - Causes the playback of the message to be skipped\n"
00285 " if the channel is not in the 'up' state (i.e. it\n"
00286 " hasn't been answered yet). If this happens, the\n"
00287 " application will return immediately.\n"
00288 " n - Don't answer the channel before playing the files.\n"
00289 " m - Only break if a digit hit matches a one digit\n"
00290 " extension in the destination context.\n"
00291 "See Also: Playback (application) -- Play sound file(s) to the channel,\n"
00292 " that cannot be interrupted\n"
00293 },
00294
00295 { "Busy", pbx_builtin_busy,
00296 "Indicate the Busy condition",
00297 " Busy([timeout]): This application will indicate the busy condition to\n"
00298 "the calling channel. If the optional timeout is specified, the calling channel\n"
00299 "will be hung up after the specified number of seconds. Otherwise, this\n"
00300 "application will wait until the calling channel hangs up.\n"
00301 },
00302
00303 { "Congestion", pbx_builtin_congestion,
00304 "Indicate the Congestion condition",
00305 " Congestion([timeout]): This application will indicate the congestion\n"
00306 "condition to the calling channel. If the optional timeout is specified, the\n"
00307 "calling channel will be hung up after the specified number of seconds.\n"
00308 "Otherwise, this application will wait until the calling channel hangs up.\n"
00309 },
00310
00311 { "Goto", pbx_builtin_goto,
00312 "Jump to a particular priority, extension, or context",
00313 " Goto([[context|]extension|]priority): This application will set the current\n"
00314 "context, extension, and priority in the channel structure. After it completes, the\n"
00315 "pbx engine will continue dialplan execution at the specified location.\n"
00316 "If no specific extension, or extension and context, are specified, then this\n"
00317 "application will just set the specified priority of the current extension.\n"
00318 " At least a priority is required as an argument, or the goto will return a -1,\n"
00319 "and the channel and call will be terminated.\n"
00320 " If the location that is put into the channel information is bogus, and asterisk cannot\n"
00321 "find that location in the dialplan,\n"
00322 "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
00323 "extension in the current context. If that does not exist, it will try to execute the\n"
00324 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
00325 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
00326 "What this means is that, for example, you specify a context that does not exist, then\n"
00327 "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
00328 },
00329
00330 { "GotoIf", pbx_builtin_gotoif,
00331 "Conditional goto",
00332 " GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
00333 "context, extension, and priority in the channel structure based on the evaluation of\n"
00334 "the given condition. After this application completes, the\n"
00335 "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
00336 "The channel will continue at\n"
00337 "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
00338 "false. The labels are specified with the same syntax as used within the Goto\n"
00339 "application. If the label chosen by the condition is omitted, no jump is\n"
00340 "performed, and the execution passes to the next instruction.\n"
00341 "If the target location is bogus, and does not exist, the execution engine will try \n"
00342 "to find and execute the code in the 'i' (invalid)\n"
00343 "extension in the current context. If that does not exist, it will try to execute the\n"
00344 "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
00345 "channel is hung up, and the execution of instructions on the channel is terminated.\n"
00346 "Remember that this command can set the current context, and if the context specified\n"
00347 "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
00348 "the channel and call will both be terminated!\n"
00349 },
00350
00351 { "GotoIfTime", pbx_builtin_gotoiftime,
00352 "Conditional Goto based on the current time",
00353 " GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
00354 "This application will set the context, extension, and priority in the channel structure\n"
00355 "if the current time matches the given time specification. Otherwise, nothing is done.\n"
00356 "Further information on the time specification can be found in examples\n"
00357 "illustrating how to do time-based context includes in the dialplan.\n"
00358 "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
00359 },
00360
00361 { "ExecIfTime", pbx_builtin_execiftime,
00362 "Conditional application execution based on the current time",
00363 " ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
00364 "This application will execute the specified dialplan application, with optional\n"
00365 "arguments, if the current time matches the given time specification.\n"
00366 },
00367
00368 { "Hangup", pbx_builtin_hangup,
00369 "Hang up the calling channel",
00370 " Hangup([causecode]): This application will hang up the calling channel.\n"
00371 "If a causecode is given the channel's hangup cause will be set to the given\n"
00372 "value.\n"
00373 },
00374
00375 { "NoOp", pbx_builtin_noop,
00376 "Do Nothing",
00377 " NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
00378 "purposes. Any text that is provided as arguments to this application can be\n"
00379 "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
00380 "variables or functions without having any effect."
00381 },
00382
00383 { "Progress", pbx_builtin_progress,
00384 "Indicate progress",
00385 " Progress(): This application will request that in-band progress information\n"
00386 "be provided to the calling channel.\n"
00387 },
00388
00389 { "ResetCDR", pbx_builtin_resetcdr,
00390 "Resets the Call Data Record",
00391 " ResetCDR([options]): This application causes the Call Data Record to be\n"
00392 "reset.\n"
00393 " Options:\n"
00394 " w -- Store the current CDR record before resetting it.\n"
00395 " a -- Store any stacked records.\n"
00396 " v -- Save CDR variables.\n"
00397 },
00398
00399 { "Ringing", pbx_builtin_ringing,
00400 "Indicate ringing tone",
00401 " Ringing(): This application will request that the channel indicate a ringing\n"
00402 "tone to the user.\n"
00403 },
00404
00405 { "SayNumber", pbx_builtin_saynumber,
00406 "Say Number",
00407 " SayNumber(digits[,gender]): This application will play the sounds that\n"
00408 "correspond to the given number. Optionally, a gender may be specified.\n"
00409 "This will use the language that is currently set for the channel. See the\n"
00410 "LANGUAGE function for more information on setting the language for the channel.\n"
00411 },
00412
00413 { "SayDigits", pbx_builtin_saydigits,
00414 "Say Digits",
00415 " SayDigits(digits): This application will play the sounds that correspond\n"
00416 "to the digits of the given number. This will use the language that is currently\n"
00417 "set for the channel. See the LANGUAGE function for more information on setting\n"
00418 "the language for the channel.\n"
00419 },
00420
00421 { "SayAlpha", pbx_builtin_saycharacters,
00422 "Say Alpha",
00423 " SayAlpha(string): This application will play the sounds that correspond to\n"
00424 "the letters of the given string.\n"
00425 },
00426
00427 { "SayPhonetic", pbx_builtin_sayphonetic,
00428 "Say Phonetic",
00429 " SayPhonetic(string): This application will play the sounds from the phonetic\n"
00430 "alphabet that correspond to the letters in the given string.\n"
00431 },
00432
00433 { "SetAMAFlags", pbx_builtin_setamaflags,
00434 "Set the AMA Flags",
00435 " SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
00436 " billing purposes.\n"
00437 },
00438
00439 { "SetGlobalVar", pbx_builtin_setglobalvar,
00440 "Set a global variable to a given value",
00441 " SetGlobalVar(variable=value): This application sets a given global variable to\n"
00442 "the specified value.\n"
00443 "\n\nThis application is deprecated in favor of Set(GLOBAL(var)=value)\n"
00444 },
00445
00446 { "Set", pbx_builtin_setvar,
00447 "Set channel variable(s) or function value(s)",
00448 " Set(name1=value1|name2=value2|..[|options])\n"
00449 "This function can be used to set the value of channel variables or dialplan\n"
00450 "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
00451 "if the variable name is prefixed with _, the variable will be inherited into\n"
00452 "channels created from the current channel. If the variable name is prefixed\n"
00453 "with __, the variable will be inherited into channels created from the current\n"
00454 "channel and all children channels.\n"
00455 " Options:\n"
00456 " g - Set variable globally instead of on the channel\n"
00457 " (applies only to variables, not functions)\n"
00458 "\n\nThe use of Set to set multiple variables at once and the g flag have both\n"
00459 "been deprecated. Please use multiple Set calls and the GLOBAL() dialplan\n"
00460 "function instead.\n"
00461 },
00462
00463 { "ImportVar", pbx_builtin_importvar,
00464 "Import a variable from a channel into a new variable",
00465 " ImportVar(newvar=channelname|variable): This application imports a variable\n"
00466 "from the specified channel (as opposed to the current one) and stores it as\n"
00467 "a variable in the current channel (the channel that is calling this\n"
00468 "application). Variables created by this application have the same inheritance\n"
00469 "properties as those created with the Set application. See the documentation for\n"
00470 "Set for more information.\n"
00471 },
00472
00473 { "Wait", pbx_builtin_wait,
00474 "Waits for some time",
00475 " Wait(seconds): This application waits for a specified number of seconds.\n"
00476 "Then, dialplan execution will continue at the next priority.\n"
00477 " Note that the seconds can be passed with fractions of a second. For example,\n"
00478 "'1.5' will ask the application to wait for 1.5 seconds.\n"
00479 },
00480
00481 { "WaitExten", pbx_builtin_waitexten,
00482 "Waits for an extension to be entered",
00483 " WaitExten([seconds][|options]): This application waits for the user to enter\n"
00484 "a new extension for a specified number of seconds.\n"
00485 " Note that the seconds can be passed with fractions of a second. For example,\n"
00486 "'1.5' will ask the application to wait for 1.5 seconds.\n"
00487 " Options:\n"
00488 " m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
00489 " Optionally, specify the class for music on hold within parenthesis.\n"
00490 "See Also: Playback(application), Background(application).\n"
00491 },
00492
00493 };
00494
00495 static struct ast_context *contexts;
00496 AST_RWLOCK_DEFINE_STATIC(conlock);
00497
00498 static AST_LIST_HEAD_STATIC(apps, ast_app);
00499
00500 static AST_LIST_HEAD_STATIC(switches, ast_switch);
00501
00502 static int stateid = 1;
00503
00504
00505
00506
00507
00508
00509 static AST_LIST_HEAD_STATIC(hints, ast_hint);
00510 struct ast_state_cb *statecbs;
00511
00512
00513
00514
00515 int pbx_exec(struct ast_channel *c,
00516 struct ast_app *app,
00517 void *data)
00518 {
00519 int res;
00520
00521 const char *saved_c_appl;
00522 const char *saved_c_data;
00523
00524 if (c->cdr && !ast_check_hangup(c))
00525 ast_cdr_setapp(c->cdr, app->name, data);
00526
00527
00528 saved_c_appl= c->appl;
00529 saved_c_data= c->data;
00530
00531 c->appl = app->name;
00532 c->data = data;
00533
00534 if (app->module) {
00535
00536 }
00537 res = app->execute(c, S_OR(data, ""));
00538 if (app->module) {
00539
00540 }
00541
00542 c->appl = saved_c_appl;
00543 c->data = saved_c_data;
00544 return res;
00545 }
00546
00547
00548
00549 #define AST_PBX_MAX_STACK 128
00550
00551
00552
00553 struct ast_app *pbx_findapp(const char *app)
00554 {
00555 struct ast_app *tmp;
00556
00557 AST_LIST_LOCK(&apps);
00558 AST_LIST_TRAVERSE(&apps, tmp, list) {
00559 if (!strcasecmp(tmp->name, app))
00560 break;
00561 }
00562 AST_LIST_UNLOCK(&apps);
00563
00564 return tmp;
00565 }
00566
00567 static struct ast_switch *pbx_findswitch(const char *sw)
00568 {
00569 struct ast_switch *asw;
00570
00571 AST_LIST_LOCK(&switches);
00572 AST_LIST_TRAVERSE(&switches, asw, list) {
00573 if (!strcasecmp(asw->name, sw))
00574 break;
00575 }
00576 AST_LIST_UNLOCK(&switches);
00577
00578 return asw;
00579 }
00580
00581 static inline int include_valid(struct ast_include *i)
00582 {
00583 if (!i->hastime)
00584 return 1;
00585
00586 return ast_check_timing(&(i->timing));
00587 }
00588
00589 static void pbx_destroy(struct ast_pbx *p)
00590 {
00591 free(p);
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 static int ext_cmp1(const char **p)
00651 {
00652 uint32_t chars[8];
00653 int c, cmin = 0xff, count = 0;
00654 const char *end;
00655
00656
00657
00658
00659 while ( (c = *(*p)++) && (c == ' ' || c == '-') )
00660 ;
00661
00662
00663 switch (c) {
00664 default:
00665 return 0x0000 | (c & 0xff);
00666
00667 case 'N':
00668 return 0x0700 | '2' ;
00669
00670 case 'X':
00671 return 0x0900 | '0';
00672
00673 case 'Z':
00674 return 0x0800 | '1';
00675
00676 case '.':
00677 return 0x10000;
00678
00679 case '!':
00680 return 0x20000;
00681
00682 case '\0':
00683 *p = NULL;
00684 return 0x30000;
00685
00686 case '[':
00687 break;
00688 }
00689
00690 end = strchr(*p, ']');
00691
00692 if (end == NULL) {
00693 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
00694 return 0x40000;
00695 }
00696
00697 bzero(chars, sizeof(chars));
00698 for (; *p < end ; (*p)++) {
00699 unsigned char c1, c2;
00700 c1 = (unsigned char)((*p)[0]);
00701 if (*p + 2 < end && (*p)[1] == '-') {
00702 c2 = (unsigned char)((*p)[2]);
00703 *p += 2;
00704 } else
00705 c2 = c1;
00706 if (c1 < cmin)
00707 cmin = c1;
00708 for (; c1 <= c2; c1++) {
00709 uint32_t mask = 1 << (c1 % 32);
00710 if ( (chars[ c1 / 32 ] & mask) == 0)
00711 count += 0x100;
00712 chars[ c1 / 32 ] |= mask;
00713 }
00714 }
00715 (*p)++;
00716 return count == 0 ? 0x30000 : (count | cmin);
00717 }
00718
00719
00720
00721
00722 static int ext_cmp(const char *a, const char *b)
00723 {
00724
00725
00726
00727
00728 int ret = 0;
00729
00730 if (a[0] != '_')
00731 return (b[0] == '_') ? -1 : strcmp(a, b);
00732
00733
00734 if (b[0] != '_')
00735 return 1;
00736 #if 0
00737 return strcmp(a, b);
00738 #endif
00739
00740 while (!ret && a && b)
00741 ret = ext_cmp1(&a) - ext_cmp1(&b);
00742 if (ret == 0)
00743 return 0;
00744 else
00745 return (ret > 0) ? 1 : -1;
00746 }
00747
00748
00749
00750
00751
00752
00753
00754 enum ext_match_t {
00755 E_MATCHMORE = 0x00,
00756 E_CANMATCH = 0x01,
00757 E_MATCH = 0x02,
00758 E_MATCH_MASK = 0x03,
00759 E_SPAWN = 0x12,
00760 E_FINDLABEL = 0x22
00761 };
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
00773 {
00774 mode &= E_MATCH_MASK;
00775
00776 if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) )
00777 return 1;
00778
00779 if (pattern[0] != '_') {
00780 int ld = strlen(data), lp = strlen(pattern);
00781
00782 if (lp < ld)
00783 return 0;
00784
00785 if (mode == E_MATCH)
00786 return !strcmp(pattern, data);
00787 if (ld == 0 || !strncasecmp(pattern, data, ld))
00788 return (mode == E_MATCHMORE) ? lp > ld : 1;
00789 else
00790 return 0;
00791 }
00792 pattern++;
00793
00794
00795
00796
00797 while (*data && *pattern && *pattern != '/') {
00798 const char *end;
00799
00800 if (*data == '-') {
00801 data++;
00802 continue;
00803 }
00804 switch (toupper(*pattern)) {
00805 case '[':
00806 end = strchr(pattern+1, ']');
00807 if (end == NULL) {
00808 ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
00809 return 0;
00810 }
00811 for (pattern++; pattern != end; pattern++) {
00812 if (pattern+2 < end && pattern[1] == '-') {
00813 if (*data >= pattern[0] && *data <= pattern[2])
00814 break;
00815 else {
00816 pattern += 2;
00817 continue;
00818 }
00819 } else if (*data == pattern[0])
00820 break;
00821 }
00822 if (pattern == end)
00823 return 0;
00824 pattern = end;
00825 break;
00826 case 'N':
00827 if (*data < '2' || *data > '9')
00828 return 0;
00829 break;
00830 case 'X':
00831 if (*data < '0' || *data > '9')
00832 return 0;
00833 break;
00834 case 'Z':
00835 if (*data < '1' || *data > '9')
00836 return 0;
00837 break;
00838 case '.':
00839 return 1;
00840 case '!':
00841 return 2;
00842 case ' ':
00843 case '-':
00844 data--;
00845 break;
00846 default:
00847 if (*data != *pattern)
00848 return 0;
00849 }
00850 data++;
00851 pattern++;
00852 }
00853 if (*data)
00854 return 0;
00855
00856
00857
00858
00859 if (*pattern == '\0' || *pattern == '/')
00860 return (mode == E_MATCHMORE) ? 0 : 1;
00861 else if (*pattern == '!')
00862 return 2;
00863 else
00864 return (mode == E_MATCH) ? 0 : 1;
00865 }
00866
00867
00868
00869
00870
00871 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
00872 {
00873 int i;
00874 static int prof_id = -2;
00875 if (prof_id == -2)
00876 prof_id = ast_add_profile("ext_match", 0);
00877 ast_mark(prof_id, 1);
00878 i = _extension_match_core(pattern, data, mode);
00879 ast_mark(prof_id, 0);
00880 return i;
00881 }
00882
00883 int ast_extension_match(const char *pattern, const char *data)
00884 {
00885 return extension_match_core(pattern, data, E_MATCH);
00886 }
00887
00888 int ast_extension_close(const char *pattern, const char *data, int needmore)
00889 {
00890 if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
00891 ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
00892 return extension_match_core(pattern, data, needmore);
00893 }
00894
00895 struct ast_context *ast_context_find(const char *name)
00896 {
00897 struct ast_context *tmp = NULL;
00898
00899 ast_rdlock_contexts();
00900
00901 while ( (tmp = ast_walk_contexts(tmp)) ) {
00902 if (!name || !strcasecmp(name, tmp->name))
00903 break;
00904 }
00905
00906 ast_unlock_contexts();
00907
00908 return tmp;
00909 }
00910
00911 #define STATUS_NO_CONTEXT 1
00912 #define STATUS_NO_EXTENSION 2
00913 #define STATUS_NO_PRIORITY 3
00914 #define STATUS_NO_LABEL 4
00915 #define STATUS_SUCCESS 5
00916
00917 static int matchcid(const char *cidpattern, const char *callerid)
00918 {
00919
00920
00921
00922 if (ast_strlen_zero(callerid))
00923 return ast_strlen_zero(cidpattern) ? 1 : 0;
00924
00925 return ast_extension_match(cidpattern, callerid);
00926 }
00927
00928
00929 struct pbx_find_info {
00930 #if 0
00931 const char *context;
00932 const char *exten;
00933 int priority;
00934 #endif
00935
00936 char *incstack[AST_PBX_MAX_STACK];
00937 int stacklen;
00938 int status;
00939 struct ast_switch *swo;
00940 const char *data;
00941 const char *foundcontext;
00942 };
00943
00944 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
00945 struct ast_context *bypass, struct pbx_find_info *q,
00946 const char *context, const char *exten, int priority,
00947 const char *label, const char *callerid, enum ext_match_t action)
00948 {
00949 int x, res;
00950 struct ast_context *tmp;
00951 struct ast_exten *e, *eroot;
00952 struct ast_include *i;
00953 struct ast_sw *sw;
00954 char *tmpdata = NULL;
00955
00956
00957 if (q->stacklen == 0) {
00958 q->status = STATUS_NO_CONTEXT;
00959 q->swo = NULL;
00960 q->data = NULL;
00961 q->foundcontext = NULL;
00962 }
00963
00964 if (q->stacklen >= AST_PBX_MAX_STACK) {
00965 ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
00966 return NULL;
00967 }
00968
00969 for (x = 0; x < q->stacklen; x++) {
00970 if (!strcasecmp(q->incstack[x], context))
00971 return NULL;
00972 }
00973 if (bypass)
00974 tmp = bypass;
00975 else {
00976 tmp = NULL;
00977 while ((tmp = ast_walk_contexts(tmp)) ) {
00978 if (!strcmp(tmp->name, context))
00979 break;
00980 }
00981 if (!tmp)
00982 return NULL;
00983 }
00984 if (q->status < STATUS_NO_EXTENSION)
00985 q->status = STATUS_NO_EXTENSION;
00986
00987
00988 eroot = NULL;
00989 while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
00990 int