Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

pbx.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Core PBX routines.
00005  * 
00006  * Copyright (C) 1999, Mark Spencer
00007  *
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #include <asterisk/lock.h>
00015 #include <asterisk/cli.h>
00016 #include <asterisk/pbx.h>
00017 #include <asterisk/channel.h>
00018 #include <asterisk/options.h>
00019 #include <asterisk/logger.h>
00020 #include <asterisk/file.h>
00021 #include <asterisk/callerid.h>
00022 #include <asterisk/cdr.h>
00023 #include <asterisk/config.h>
00024 #include <asterisk/term.h>
00025 #include <asterisk/manager.h>
00026 #include <asterisk/ast_expr.h>
00027 #include <asterisk/channel_pvt.h>
00028 #include <asterisk/linkedlists.h>
00029 #include <asterisk/say.h>
00030 #include <string.h>
00031 #include <unistd.h>
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <setjmp.h>
00035 #include <ctype.h>
00036 #include <errno.h>
00037 #include <time.h>
00038 #include <sys/time.h>
00039 #include "asterisk.h"
00040 
00041 /*
00042  * I M P O R T A N T :
00043  *
00044  *    The speed of extension handling will likely be among the most important
00045  * aspects of this PBX.  The switching scheme as it exists right now isn't
00046  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
00047  * of priorities, but a constant search time here would be great ;-) 
00048  *
00049  */
00050 
00051 
00052 struct ast_context;
00053 
00054 /* An extension */
00055 struct ast_exten {
00056    char exten[AST_MAX_EXTENSION];
00057    int matchcid;
00058    char cidmatch[AST_MAX_EXTENSION];
00059    int priority;
00060    /* An extension */
00061    struct ast_context *parent;
00062    /* Application to execute */
00063    char app[AST_MAX_EXTENSION];
00064    /* Data to use */
00065    void *data;
00066    /* Data destructor */
00067    void (*datad)(void *);
00068    /* Next higher priority with our extension */
00069    struct ast_exten *peer;
00070    /* Registrar */
00071    char *registrar;
00072    /* Extension with a greater ID */
00073    struct ast_exten *next;
00074 };
00075 
00076 struct ast_include {
00077    char name[AST_MAX_EXTENSION];
00078    char rname[AST_MAX_EXTENSION];
00079    char *registrar;
00080    int hastime;
00081    unsigned int monthmask;
00082    unsigned int daymask;
00083    unsigned int dowmask;
00084    unsigned int minmask[24];
00085    struct ast_include *next;
00086 };
00087 
00088 struct ast_sw {
00089    char name[AST_MAX_EXTENSION];
00090    char *registrar;
00091    char data[AST_MAX_EXTENSION];
00092    struct ast_sw *next;
00093 };
00094 
00095 struct ast_ignorepat {
00096    char pattern[AST_MAX_EXTENSION];
00097    char *registrar;
00098    struct ast_ignorepat *next;
00099 };
00100 
00101 /* An extension context */
00102 struct ast_context {
00103    /* Name of the context */
00104    char name[AST_MAX_EXTENSION];
00105    /* A lock to prevent multiple threads from clobbering the context */
00106    ast_mutex_t lock;
00107    /* The root of the list of extensions */
00108    struct ast_exten *root;
00109    /* Link them together */
00110    struct ast_context *next;
00111    /* Include other contexts */
00112    struct ast_include *includes;
00113    /* Patterns for which to continue playing dialtone */
00114    struct ast_ignorepat *ignorepats;
00115    /* Registrar */
00116    char *registrar;
00117    /* Alternative switches */
00118    struct ast_sw *alts;
00119 };
00120 
00121 
00122 /* An application */
00123 struct ast_app {
00124    /* Name of the application */
00125    char name[AST_MAX_APP];
00126    int (*execute)(struct ast_channel *chan, void *data);
00127    char *synopsis;
00128    char *description;
00129    struct ast_app *next;
00130 };
00131 
00132 /* An extension state notify */
00133 struct ast_state_cb {
00134     int id;
00135     void *data;
00136     ast_state_cb_type callback;
00137     struct ast_state_cb *next;
00138 };
00139        
00140 struct ast_hint {
00141     struct ast_exten *exten;
00142     int laststate; 
00143     struct ast_state_cb *callbacks;
00144     struct ast_hint *next;
00145 };
00146 
00147 
00148 static int pbx_builtin_prefix(struct ast_channel *, void *);
00149 static int pbx_builtin_suffix(struct ast_channel *, void *);
00150 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
00151 static int pbx_builtin_answer(struct ast_channel *, void *);
00152 static int pbx_builtin_goto(struct ast_channel *, void *);
00153 static int pbx_builtin_hangup(struct ast_channel *, void *);
00154 static int pbx_builtin_background(struct ast_channel *, void *);
00155 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
00156 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
00157 static int pbx_builtin_atimeout(struct ast_channel *, void *);
00158 static int pbx_builtin_wait(struct ast_channel *, void *);
00159 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
00160 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00161 static int pbx_builtin_setaccount(struct ast_channel *, void *);
00162 static int pbx_builtin_ringing(struct ast_channel *, void *);
00163 static int pbx_builtin_congestion(struct ast_channel *, void *);
00164 static int pbx_builtin_busy(struct ast_channel *, void *);
00165 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
00166 static int pbx_builtin_noop(struct ast_channel *, void *);
00167 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00168 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00169 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00170 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00171 int pbx_builtin_setvar(struct ast_channel *, void *);
00172 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
00173 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
00174 
00175 static struct varshead globals = AST_LIST_HEAD_INITIALIZER(varshead);
00176 
00177 static struct pbx_builtin {
00178    char name[AST_MAX_APP];
00179    int (*execute)(struct ast_channel *chan, void *data);
00180    char *synopsis;
00181    char *description;
00182 } builtins[] = 
00183 {
00184    /* These applications are built into the PBX core and do not
00185       need separate modules
00186       
00187        */
00188 
00189    { "AbsoluteTimeout", pbx_builtin_atimeout,
00190 "Set absolute maximum time of call",
00191 "  AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
00192 "for a call.  A setting of 0 disables the timeout.  Always returns 0.\n" },
00193 
00194    { "Answer", pbx_builtin_answer, 
00195 "Answer a channel if ringing", 
00196 "  Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
00197 "Returns 0 unless it tries to answer the channel and fails.\n"   },
00198 
00199    { "BackGround", pbx_builtin_background,
00200 "Play a file while awaiting extension",
00201 "  Background(filename): Plays a given file, while simultaneously waiting for\n"
00202 "the user to begin typing an extension. The  timeouts  do not count until the\n"
00203 "last BackGround application as ended. Always returns 0.\n" },
00204 
00205    { "Busy", pbx_builtin_busy,
00206 "Indicate busy condition and stop",
00207 "  Busy(): Requests that the channel indicate busy condition and then waits\n"
00208 "for the user to hang up.  Always returns -1." },
00209 
00210    { "Congestion", pbx_builtin_congestion,
00211 "Indicate congestion and stop",
00212 "  Congestion(): Requests that the channel indicate congestion and then\n"
00213 "waits for the user to hang up.  Always returns -1." },
00214 
00215    { "DigitTimeout", pbx_builtin_dtimeout,
00216 "Set maximum timeout between digits",
00217 "  DigitTimeout(seconds): Set the  maximum  amount of time permitted between\n"
00218 "digits when the user is typing in an extension.  When this timeout expires,\n"
00219 "after the user has started to  type  in an extension, the extension will be\n"
00220 "considered  complete, and  will be interpreted.  Note that if an  extension\n"
00221 "typed in is valid, it will not have to timeout to be tested,  so  typically\n"
00222 "at  the  expiry of  this timeout, the  extension will be considered invalid\n"
00223 "(and  thus  control  would be passed to the 'i' extension, or if it doesn't\n"
00224 "exist the call would be terminated).  Always returns 0.\n" },
00225 
00226    { "Goto", pbx_builtin_goto, 
00227 "Goto a particular priority, extension, or context",
00228 "  Goto([[context|]extension|]priority):  Set the  priority to the specified\n"
00229 "value, optionally setting the extension and optionally the context as well.\n"
00230 "The extension BYEXTENSION is special in that it uses the current extension,\n"
00231 "thus  permitting  you  to go to a different  context, without  specifying a\n"
00232 "specific extension. Always returns 0, even if the given context, extension,\n"
00233 "or priority is invalid.\n" },
00234 
00235    { "GotoIf", pbx_builtin_gotoif,
00236 "Conditional goto",
00237 "  GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
00238 "true, to label2 if condition is false. Either label1 or label2 may be\n"
00239 "omitted (in that case, we just don't take the particular branch) but not\n"
00240 "both.  Look for the condition syntax in examples or documentation." },
00241 
00242    { "GotoIfTime", pbx_builtin_gotoiftime,
00243 "Conditional goto on current time",
00244 "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
00245 "If the current time matches the specified time, then branch to the specified\n"
00246 "extension.  Each of the elements may be specified either as '*' (for always)\n"
00247 "or as a range.  See the include syntax." },
00248 
00249    { "Hangup", pbx_builtin_hangup,
00250 "Unconditional hangup",
00251 "  Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" },
00252 
00253    { "NoOp", pbx_builtin_noop,
00254 "No operation",
00255 "  NoOp(): No-operation; Does nothing." },
00256 
00257    { "Prefix", pbx_builtin_prefix, 
00258 "Prepend leading digits",
00259 "  Prefix(digits): Prepends the  digit  string  specified  by  digits to the\n"
00260 "channel's associated extension. For example, the number 1212 when  prefixed\n"
00261 "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
00262 "continue processing at the next priority for the *new* extension.\n"
00263 "  So, for example, if priority  3  of 1212 is  Prefix  555, the  next  step\n"
00264 "executed will be priority 4 of 5551212. If  you  switch  into an  extension\n"
00265 "which has no first step, the PBX will treat it as though the user dialed an\n"
00266 "invalid extension.\n" },
00267 
00268    { "ResetCDR", pbx_builtin_resetcdr,
00269 "Resets the Call Data Record",
00270 "  ResetCDR([options]):  Causes the Call Data Record to be reset, optionally\n"
00271 "storing the current CDR  before zeroing it out (if 'w' option is specifed).\n"
00272 "record WILL be stored.  Always returns 0.\n"  },
00273 
00274    { "ResponseTimeout", pbx_builtin_rtimeout,
00275 "Set maximum timeout awaiting response",
00276 "  ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
00277 "falling through a series of priorities for a channel in which the user may\n"
00278 "begin typing an extension.  If the user does not type an extension in this\n"
00279 "amount of time, control will pass to the 't' extension if  it  exists, and\n"
00280 "if not the call would be terminated.  Always returns 0.\n"  },
00281 
00282    { "Ringing", pbx_builtin_ringing,
00283 "Indicate ringing tone",
00284 "  Ringing(): Request that the channel indicate ringing tone to the user.\n"
00285 "Always returns 0.\n" },
00286 
00287    { "SayNumber", pbx_builtin_saynumber,
00288 "Say Number",
00289 "  SayNumber(digits): Says the passed number\n" },
00290 
00291    { "SayDigits", pbx_builtin_saydigits,
00292 "Say Digits",
00293 "  SayDigits(digits): Says the passed digits\n" },
00294 
00295    { "SetAccount", pbx_builtin_setaccount,
00296 "Sets account code",
00297 "  SetAccount([account]):  Set  the  channel account code for billing\n"
00298 "purposes. Always returns 0.\n"  },
00299 
00300    { "SetGlobalVar", pbx_builtin_setglobalvar,
00301 "Set variable to value",
00302 "  SetGlobalVar(#n=value): Sets global variable n to value" },
00303 
00304    { "SetLanguage", pbx_builtin_setlanguage,
00305 "Sets user language",
00306 "  SetLanguage(language):  Set  the  channel  language to 'language'.  This\n"
00307 "information is used for the generation of numbers, and to select a natural\n"
00308 "language file when available.  For example, if language is set to 'fr' and\n"
00309 "the file 'demo-congrats' is requested  to  be  played,  if the file 'fr/demo-\n"
00310 "congrats' exists, then it will play that file, and if not will play the\n"
00311 "normal 'demo-congrats'. Always returns 0.\n"  },
00312 
00313    { "SetVar", pbx_builtin_setvar,
00314 "Set variable to value",
00315 "  Setvar(#n=value): Sets variable n to value" },
00316 
00317    { "StripMSD", pbx_builtin_stripmsd,
00318 "Strip leading digits",
00319 "  StripMSD(count): Strips the leading  'count'  digits  from  the  channel's\n"
00320 "associated extension. For example, the  number  5551212 when stripped with a\n"
00321 "count of 3 would be changed to 1212.  This app always returns 0, and the PBX\n"
00322 "will continue processing at the next priority for the *new* extension.\n"
00323 "  So, for  example, if  priority 3 of 5551212  is  StripMSD 3, the next step\n"
00324 "executed will be priority 4 of 1212.  If you switch into an  extension which\n"
00325 "has no first step, the PBX will treat it as though the user dialed an\n"
00326 "invalid extension.\n" },
00327 
00328    { "Suffix", pbx_builtin_suffix, 
00329 "Append trailing digits",
00330 "  Suffix(digits): Appends the  digit  string  specified  by  digits to the\n"
00331 "channel's associated extension. For example, the number 555 when  suffixed\n"
00332 "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
00333 "continue processing at the next priority for the *new* extension.\n"
00334 "  So, for example, if priority  3  of  555 is Suffix 1212, the  next  step\n"
00335 "executed will be priority 4 of 5551212. If  you  switch  into an  extension\n"
00336 "which has no first step, the PBX will treat it as though the user dialed an\n"
00337 "invalid extension.\n" },
00338 
00339    { "Wait", pbx_builtin_wait, 
00340 "Waits for some time", 
00341 "  Wait(seconds): Waits for a specified number of seconds, then returns 0.\n" },
00342 
00343 };
00344 
00345 /* Lock for the application list */
00346 static ast_mutex_t applock = AST_MUTEX_INITIALIZER;
00347 static struct ast_context *contexts = NULL;
00348 /* Lock for the ast_context list */
00349 static ast_mutex_t conlock = AST_MUTEX_INITIALIZER;
00350 static struct ast_app *apps = NULL;
00351 
00352 /* Lock for switches */
00353 static ast_mutex_t switchlock = AST_MUTEX_INITIALIZER;
00354 struct ast_switch *switches = NULL;
00355 
00356 /* Lock for extension state notifys */
00357 static ast_mutex_t hintlock = AST_MUTEX_INITIALIZER;
00358 static int stateid = 1;
00359 struct ast_hint *hints = NULL;
00360 struct ast_state_cb *statecbs = NULL;
00361 
00362 int pbx_exec(struct ast_channel *c, /* Channel */
00363                struct ast_app *app,
00364                void *data,          /* Data for execution */
00365                int newstack)        /* Force stack increment */
00366 {
00367    /* This function is special.  It saves the stack so that no matter
00368       how many times it is called, it returns to the same place */
00369    int res;
00370    int stack = c->stack;
00371    int (*execute)(struct ast_channel *chan, void *data) = app->execute; 
00372    if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
00373       /* Don't allow us to go over the max number of stacks we
00374          permit saving. */
00375       ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
00376       return -1;
00377    }
00378    if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
00379       /* Okay, here's where it gets weird.  If newstack is non-zero, 
00380          then we increase the stack increment, but setjmp is not going
00381          to return until longjmp is called -- when the application
00382          exec'd is finished running. */
00383       if (res == 1)
00384          res = 0;
00385       if (c->stack != stack + 1) 
00386          ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
00387       else if (c->app[c->stack])
00388          ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
00389       c->stack = stack;
00390       return res;
00391    } else {
00392       if (c->cdr)
00393          ast_cdr_setapp(c->cdr, app->name, data);
00394       c->appl = app->name;
00395       c->data = data;      
00396       res = execute(c, data);
00397       c->appl = NULL;
00398       c->data = NULL;      
00399       /* Any application that returns, we longjmp back, just in case. */
00400       if (c->stack != stack + 1)
00401          ast_log(LOG_WARNING, "Stack is not at expected value\n");
00402       longjmp(c->jmp[stack+1], res);
00403       /* Never returns */
00404    }
00405 }
00406 
00407 
00408 /* Go no deeper than this through includes (not counting loops) */
00409 #define AST_PBX_MAX_STACK  64
00410 
00411 #define HELPER_EXISTS 0
00412 #define HELPER_SPAWN 1
00413 #define HELPER_EXEC 2
00414 #define HELPER_CANMATCH 3
00415 #define HELPER_MATCHMORE 4
00416 
00417 struct ast_app *pbx_findapp(char *app) 
00418 {
00419    struct ast_app *tmp;
00420    if (ast_mutex_lock(&applock)) {
00421       ast_log(LOG_WARNING, "Unable to obtain application lock\n");
00422       return NULL;
00423    }
00424    tmp = apps;
00425    while(tmp) {
00426       if (!strcasecmp(tmp->name, app))
00427          break;
00428       tmp = tmp->next;
00429    }
00430    ast_mutex_unlock(&applock);
00431    return tmp;
00432 }
00433 
00434 static struct ast_switch *pbx_findswitch(char *sw)
00435 {
00436    struct ast_switch *asw;
00437    if (ast_mutex_lock(&switchlock)) {
00438       ast_log(LOG_WARNING, "Unable to obtain application lock\n");
00439       return NULL;
00440    }
00441    asw = switches;
00442    while(asw) {
00443       if (!strcasecmp(asw->name, sw))
00444          break;
00445       asw = asw->next;
00446    }
00447    ast_mutex_unlock(&switchlock);
00448    return asw;
00449 }
00450 
00451 static inline int include_valid(struct ast_include *i)
00452 {
00453    struct tm tm;
00454    time_t t;
00455    if (!i->hastime)
00456       return 1;
00457    time(&t);
00458    localtime_r(&t,&tm);
00459 
00460    /* If it's not the right month, return */
00461    if (!(i->monthmask & (1 << tm.tm_mon))) {
00462       return 0;
00463    }
00464 
00465    /* If it's not that time of the month.... */
00466    /* Warning, tm_mday has range 1..31! */
00467    if (!(i->daymask & (1 << (tm.tm_mday-1))))
00468       return 0;
00469 
00470    /* If it's not the right day of the week */
00471    if (!(i->dowmask & (1 << tm.tm_wday)))
00472       return 0;
00473 
00474    /* Sanity check the hour just to be safe */
00475    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
00476       ast_log(LOG_WARNING, "Insane time...\n");
00477       return 0;
00478    }
00479 
00480    /* Now the tough part, we calculate if it fits
00481       in the right time based on min/hour */
00482    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
00483       return 0;
00484 
00485    /* If we got this far, then we're good */
00486    return 1;
00487 }
00488 
00489 static void pbx_destroy(struct ast_pbx *p)
00490 {
00491    free(p);
00492 }
00493 
00494 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
00495    /* All patterns begin with _ */\
00496    if (pattern[0] != '_') \
00497       return 0;\
00498    /* Start optimistic */\
00499    match=1;\
00500    pattern++;\
00501    while(match && *data && *pattern && (*pattern != '/')) {\
00502       switch(toupper(*pattern)) {\
00503       case '[': \
00504       {\
00505          int i,border=0;\
00506          char *where;\
00507          match=0;\
00508          pattern++;\
00509          where=strchr(pattern,']');\
00510          if (where)\
00511             border=(int)(where-pattern);\
00512          if (!where || border > strlen(pattern)) {\
00513             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
00514             return match;\
00515          }\
00516          for (i=0; i<border; i++) {\
00517             int res=0;\
00518             if (i+2<border)\
00519                if (pattern[i+1]=='-') {\
00520                   if (*data >= pattern[i] && *data <= pattern[i+2]) {\
00521                      res=1;\
00522                   } else {\
00523                      i+=2;\
00524                      continue;\
00525                   }\
00526                }\
00527             if (res==1 || *data==pattern[i]) {\
00528                match = 1;\
00529                break;\
00530             }\
00531          }\
00532          pattern+=border;\
00533          break;\
00534       }\
00535       case 'N':\
00536          if ((*data < '2') || (*data > '9'))\
00537             match=0;\
00538          break;\
00539       case 'X':\
00540          if ((*data < '0') || (*data > '9'))\
00541             match = 0;\
00542          break;\
00543       case 'Z':\
00544          if ((*data < '1') || (*data > '9'))\
00545             match = 0;\
00546          break;\
00547       case '.':\
00548          /* Must match */\
00549          return 1;\
00550       case ' ':\
00551       case '-':\
00552          /* Ignore these characters */\
00553          data--;\
00554          break;\
00555       default:\
00556          if (*data != *pattern)\
00557             match =0;\
00558       }\
00559       data++;\
00560       pattern++;\
00561    }\
00562 }
00563 
00564 int ast_extension_match(char *pattern, char *data)
00565 {
00566    int match;
00567    /* If they're the same return */
00568    if (!strcmp(pattern, data))
00569       return 1;
00570    EXTENSION_MATCH_CORE(data,pattern,match);
00571    /* Must be at the end of both */
00572    if (*data || (*pattern && (*pattern != '/')))
00573       match = 0;
00574    return match;
00575 }
00576 
00577 static int extension_close(char *pattern, char *data, int needmore)
00578 {
00579    int match;
00580    /* If "data" is longer, it can'be a subset of pattern unless
00581       pattern is a pattern match */
00582    if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
00583       return 0;
00584    
00585    if ((!strlen((char *)data) || !strncasecmp(pattern, data, strlen(data))) && 
00586       (!needmore || (strlen(pattern) > strlen(data)))) {
00587       return 1;
00588    }
00589    EXTENSION_MATCH_CORE(data,pattern,match);
00590    /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
00591    if (!needmore || *pattern) {
00592       return match;
00593    } else
00594       return 0;
00595 }
00596 
00597 struct ast_context *ast_context_find(char *name)
00598 {
00599    struct ast_context *tmp;
00600    ast_mutex_lock(&conlock);
00601    if (name) {
00602       tmp = contexts;
00603       while(tmp) {
00604          if (!strcasecmp(name, tmp->name))
00605             break;
00606          tmp = tmp->next;
00607       }
00608    } else
00609       tmp = contexts;
00610    ast_mutex_unlock(&conlock);
00611    return tmp;
00612 }
00613 
00614 #define STATUS_NO_CONTEXT   1
00615 #define STATUS_NO_EXTENSION 2
00616 #define STATUS_NO_PRIORITY  3
00617 #define STATUS_SUCCESS      4
00618 
00619 static int matchcid(char *cidpattern, char *callerid)
00620 {
00621    char tmp[AST_MAX_EXTENSION];
00622    int failresult;
00623    char *name, *num;
00624    
00625    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
00626       failing to get a number should count as a match, otherwise not */
00627 
00628 
00629    if (strlen(cidpattern))
00630       failresult = 0;
00631    else
00632       failresult = 1;
00633 
00634    if (!callerid)
00635       return failresult;
00636 
00637    /* Copy original Caller*ID */
00638    strncpy(tmp, callerid, sizeof(tmp)-1);
00639    /* Parse Number */
00640    if (ast_callerid_parse(tmp, &name, &num)) 
00641       return failresult;
00642    if (!num)
00643       return failresult;
00644    ast_shrink_phone_number(num);
00645    return ast_extension_match(cidpattern, num);
00646 }
00647 
00648 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data)
00649 {
00650    int x, res;
00651    struct ast_context *tmp;
00652    struct ast_exten *e, *eroot;
00653    struct ast_include *i;
00654    struct ast_sw *sw;
00655    struct ast_switch *asw;
00656    /* Initialize status if appropriate */
00657    if (!*stacklen) {
00658       *status = STATUS_NO_CONTEXT;
00659       *swo = NULL;
00660       *data = NULL;
00661    }
00662    /* Check for stack overflow */
00663    if (*stacklen >= AST_PBX_MAX_STACK) {
00664       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
00665       return NULL;
00666    }
00667    /* Check first to see if we've already been checked */
00668    for (x=0;x<*stacklen;x++) {
00669       if (!strcasecmp(incstack[x], context))
00670          return NULL;
00671    }
00672    tmp = contexts;
00673    while(tmp) {
00674       /* Match context */
00675       if (!strcmp(tmp->name, context)) {
00676          if (*status < STATUS_NO_EXTENSION)
00677             *status = STATUS_NO_EXTENSION;
00678          eroot = tmp->root;
00679          while(eroot) {
00680             /* Match extension */
00681             if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
00682                   ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
00683                   ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
00684                   (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
00685                   e = eroot;
00686                   if (*status < STATUS_NO_PRIORITY)
00687                      *status = STATUS_NO_PRIORITY;
00688                   while(e) {
00689                      /* Match priority */
00690                      if (e->priority == priority) {
00691                         *status = STATUS_SUCCESS;
00692                         return e;
00693                      }
00694                      e = e->peer;
00695                   }
00696             }
00697             eroot = eroot->next;
00698          }
00699          /* Check alternative switches */
00700          sw = tmp->alts;
00701          while(sw) {
00702             if ((asw = pbx_findswitch(sw->name))) {
00703                if (action == HELPER_CANMATCH)
00704                   res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
00705                else if (action == HELPER_MATCHMORE)
00706                   res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
00707                else
00708                   res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
00709                if (res) {
00710                   /* Got a match */
00711                   *swo = asw;
00712                   *data = sw->data;
00713                   return NULL;
00714                }
00715             } else {
00716                ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
00717             }
00718             sw = sw->next;
00719          }
00720          /* Setup the stack */
00721          incstack[*stacklen] = tmp->name;
00722          (*stacklen)++;
00723          /* Now try any includes we have in this context */
00724          i = tmp->includes;
00725          while(i) {
00726             if (include_valid(i)) {
00727                if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data))) 
00728                   return e;
00729                if (*swo) 
00730                   return NULL;
00731             }
00732             i = i->next;
00733          }
00734       }
00735       tmp = tmp->next;
00736    }
00737    return NULL;
00738 }
00739 
00740 static void pbx_substitute_variables_temp(struct ast_channel *c,const char *var,char **ret, char *workspace, int workspacelen)
00741 {
00742    char *first,*second;
00743    char tmpvar[80] = "";
00744    time_t thistime;
00745    struct tm brokentime;
00746    int offset,offset2;
00747    struct ast_var_t *variables;
00748    char *name, *num; /* for callerid name + num variables */
00749    struct varshead *headp=NULL;
00750     if (c) 
00751       headp=&c->varshead;
00752     *ret=NULL;
00753         /* Now we have the variable name on cp3 */
00754    if ((first=strchr(var,':'))) {
00755       strncpy(tmpvar, var, sizeof(tmpvar) - 1);
00756       first = strchr(tmpvar, ':');
00757       if (!first)
00758          first = tmpvar + strlen(tmpvar);
00759       *first='\0';
00760       pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
00761       if (!(*ret)) return;
00762       offset=atoi(first+1);
00763       if ((second=strchr(first+1,':'))) {
00764          *second='\0';
00765          offset2=atoi(second+1);
00766       } else
00767          offset2=strlen(*ret)-offset;
00768       if (abs(offset)>strlen(*ret)) {
00769          if (offset>=0) 
00770             offset=strlen(*ret);
00771          else 
00772             offset=-strlen(*ret);
00773       }
00774       if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
00775          if (offset>=0) 
00776             offset2=strlen(*ret)-offset;
00777          else 
00778             offset2=strlen(*ret)+offset;
00779       }
00780       if (offset>=0)
00781          *ret+=offset;
00782       else
00783          *ret+=strlen(*ret)+offset;
00784       (*ret)[offset2] = '\0';
00785    } else if (c && !strcmp(var, "CALLERIDNUM")) {
00786       if (c->callerid)
00787          strncpy(workspace, c->callerid, workspacelen - 1);
00788       ast_callerid_parse(workspace, &name, &num);
00789       if (num) {
00790          ast_shrink_phone_number(num);
00791          *ret = num;
00792       } else
00793          *ret = workspace;
00794    } else if (c && !strcmp(var, "CALLERIDNAME")) {
00795       if (c->callerid)
00796          strncpy(workspace, c->callerid, workspacelen - 1);
00797       ast_callerid_parse(workspace, &name, &num);
00798       if (name)
00799          *ret = name;
00800       else
00801          *ret = workspace;
00802    } else if (c && !strcmp(var, "CALLERID")) {
00803       if (c->callerid) {
00804          strncpy(workspace, c->callerid, workspacelen - 1);
00805          *ret = workspace;
00806       } else 
00807          *ret = NULL;
00808    } else if (c && !strcmp(var, "DNID")) {
00809       if (c->dnid) {
00810          strncpy(workspace, c->dnid, workspacelen - 1);
00811          *ret = workspace;
00812       } else
00813          *ret = NULL;
00814    } else if (c && !strcmp(var, "HINT")) {
00815       if (!ast_get_hint(workspace, workspacelen - 1, c, c->context, c->exten))
00816          *ret = NULL;
00817       else
00818          *ret = workspace;
00819    } else if (c && !strcmp(var, "EXTEN")) {
00820       strncpy(workspace, c->exten, workspacelen - 1);
00821       *ret = workspace;
00822    } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) && 
00823       /* XXX Remove me eventually */
00824       (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
00825       if (offset < 0)
00826          offset=0;
00827       if (offset > strlen(c->exten))
00828          offset = strlen(c->exten);
00829       strncpy(workspace, c->exten + offset, workspacelen - 1);
00830       *ret = workspace;
00831       ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
00832    } else if (c && !strcmp(var, "RDNIS")) {
00833       if (c->rdnis) {
00834          strncpy(workspace, c->rdnis, workspacelen - 1);
00835          *ret = workspace;
00836       } else
00837          *ret = NULL;
00838    } else if (c && !strcmp(var, "CONTEXT")) {
00839       strncpy(workspace, c->context, workspacelen - 1);
00840       *ret = workspace;
00841    } else if (c && !strcmp(var, "PRIORITY")) {
00842       snprintf(workspace, workspacelen, "%d", c->priority);
00843       *ret = workspace;
00844    } else if (c && !strcmp(var, "CHANNEL")) {
00845       strncpy(workspace, c->name, workspacelen - 1);
00846       *ret = workspace;
00847    } else if (c && !strcmp(var, "EPOCH")) {
00848      snprintf(workspace, workspacelen -1, "%u",(int)time(NULL));
00849      *ret = workspace;
00850    } else if (c && !strcmp(var, "DATETIME")) {
00851      thistime=time(NULL);
00852      localtime_r(&thistime, &brokentime);
00853      snprintf(workspace, workspacelen -1, "%02d%02d%04d-%02d:%02d:%02d",
00854          brokentime.tm_mday,
00855          brokentime.tm_mon+1,
00856          brokentime.tm_year+1900,
00857          brokentime.tm_hour,
00858          brokentime.tm_min,
00859          brokentime.tm_sec
00860          );
00861      *ret = workspace;
00862    } else if (c && !strcmp(var, "TIMESTAMP")) {
00863      thistime=time(NULL);
00864      localtime_r(&thistime, &brokentime);
00865       /* 20031130-150612 */
00866      snprintf(workspace, workspacelen -1, "%04d%02d%02d-%02d%02d%02d",
00867          brokentime.tm_year+1900,
00868          brokentime.tm_mon+1,
00869          brokentime.tm_mday,
00870          brokentime.tm_hour,
00871          brokentime.tm_min,
00872          brokentime.tm_sec
00873          );
00874      *ret = workspace;
00875    } else if (c && !strcmp(var, "UNIQUEID")) {
00876      snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
00877      *ret = workspace;
00878         } else if (c && !strcmp(var, "HANGUPCAUSE")) {
00879           snprintf(workspace, workspacelen -1, "%i", c->hangupcause);
00880           *ret = workspace;
00881         } else if (c && !strcmp(var, "ACCOUNTCODE")) {
00882           strncpy(workspace, c->accountcode, workspacelen - 1);
00883           *ret = workspace;
00884    } else {
00885       if (c) {
00886          AST_LIST_TRAVERSE(headp,variables,entries) {
00887 #if 0
00888             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
00889 #endif
00890             if (strcasecmp(ast_var_name(variables),var)==0) {
00891                *ret=ast_var_value(variables);
00892                if (*ret) {
00893                   strncpy(workspace, *ret, workspacelen - 1);
00894                   *ret = workspace;
00895                }
00896                break;
00897             }
00898          }
00899       }
00900       if (!(*ret)) {
00901          /* Try globals */
00902          AST_LIST_TRAVERSE(&globals,variables,entries) {
00903 #if 0
00904             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
00905 #endif
00906             if (strcasecmp(ast_var_name(variables),var)==0) {
00907                *ret=ast_var_value(variables);
00908                if (*ret) {
00909                   strncpy(workspace, *ret, workspacelen - 1);
00910                   *ret = workspace;
00911                }
00912             }
00913          }
00914       }
00915       if (!(*ret)) {
00916          int len=strlen(var);
00917          int len_env=strlen("ENV(");
00918          if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
00919             char cp3[80] = "";
00920             strncpy(cp3, var, sizeof(cp3) - 1);
00921             cp3[len-1]='\0';
00922             *ret=getenv(cp3+len_env);
00923             if (*ret) {
00924                strncpy(workspace, *ret, workspacelen - 1);
00925                *ret = workspace;
00926             }
00927          }
00928       }
00929       if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
00930          int len=strlen(var);
00931          int len_len=4;
00932          if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
00933             char cp3[80];
00934             strncpy(cp3, var, sizeof(cp3) - 1);
00935             cp3[len-len_len-1]='\0';
00936             sprintf(workspace,"%d",strlen(cp3));
00937             *ret = workspace;
00938          } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
00939       }
00940    }
00941 }
00942 
00943 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
00944 {
00945    char *cp4;
00946    const char *tmp, *whereweare;
00947    int length;
00948    char workspace[256];
00949    char ltmp[256], var[256];
00950    char *nextvar, *nextexp;
00951    char *vars, *vare;
00952    int pos, brackets, needsub, len;
00953 
00954    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
00955       zero-filled */
00956    whereweare=tmp=cp1;
00957    while(strlen(whereweare) && count) {
00958       /* Assume we're copying the whole remaining string */
00959       pos = strlen(whereweare);
00960 
00961       /* Look for a variable */
00962       nextvar = strstr(whereweare, "${");
00963       
00964       nextexp = strstr(whereweare, "$[");
00965       
00966       if (nextvar && nextexp) {
00967          if (nextvar < nextexp)
00968             nextexp = NULL;
00969          else
00970             nextvar = NULL;
00971       }
00972       
00973       /* If there is one, we only go that far */
00974       if (nextvar)
00975          pos = nextvar - whereweare;
00976       else if (nextexp)
00977          pos = nextexp - whereweare;
00978       
00979       /* Can't copy more than 'count' bytes */
00980       if (pos > count)
00981          pos = count;
00982       
00983       /* Copy that many bytes */
00984       memcpy(cp2, whereweare, pos);
00985       
00986       count -= pos;
00987       cp2 += pos;
00988       whereweare += pos;
00989       
00990       if (nextvar) {
00991          /* We have a variable.  Find the start and end, and determine
00992             if we are going to have to recursively call ourselves on the
00993             contents */
00994          vars = vare = nextvar + 2;
00995          brackets = 1;
00996          needsub = 0;
00997          
00998          /* Find the end of it */
00999          while(brackets && *vare) {
01000             if ((vare[0] == '$') && (vare[1] == '{')) {
01001                needsub++;
01002                brackets++;
01003             } else if (vare[0] == '}') {
01004                brackets--;
01005             } else if ((vare[0] == '$') && (vare[1] == '['))
01006                needsub++;
01007             vare++;
01008          }
01009          if (brackets)
01010             ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
01011          len = vare - vars - 1;
01012          
01013          /* Skip totally over variable name */
01014          whereweare += ( len + 3);
01015          
01016          /* Store variable name (and truncate) */
01017          memset(var, 0, sizeof(var));
01018          strncpy(var, vars, sizeof(var) - 1);
01019          var[len] = '\0';
01020          
01021          /* Substitute if necessary */
01022          if (needsub) {
01023             memset(ltmp, 0, sizeof(ltmp));
01024             pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
01025             vars = ltmp;
01026          } else {
01027             vars = var;
01028          }
01029          
01030          /* Retrieve variable value */
01031          strcpy(workspace, "");
01032          pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
01033          if (cp4) {
01034             length = strlen(cp4);
01035             if (length > count)
01036                length = count;
01037             memcpy(cp2, cp4, length);
01038             count -= length;
01039             cp2 += length;
01040          }
01041          
01042       } else if (nextexp) {
01043          /* We have an expression.  Find the start and end, and determine
01044             if we are going to have to recursively call ourselves on the
01045             contents */
01046          vars = vare = nextexp + 2;
01047          brackets = 1;
01048          needsub = 0;
01049          
01050          /* Find the end of it */
01051          while(brackets && *vare) {
01052             if ((vare[0] == '$') && (vare[1] == '[')) {
01053                needsub++;
01054                brackets++;
01055             } else if (vare[0] == ']') {
01056                brackets--;
01057             } else if ((vare[0] == '$') && (vare[1] == '{'))
01058                needsub++;
01059             vare++;
01060          }
01061          if (brackets)
01062             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
01063          len = vare - vars - 1;
01064          
01065          /* Skip totally over variable name */
01066          whereweare += ( len + 3);
01067          
01068          /* Store variable name (and truncate) */
01069          memset(var, 0, sizeof(var));
01070          strncpy(var, vars, sizeof(var) - 1);
01071          var[len] = '\0';
01072          
01073          /* Substitute if necessary */
01074          if (needsub) {
01075             memset(ltmp, 0, sizeof(ltmp));
01076             pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
01077             vars = ltmp;
01078          } else {
01079             vars = var;
01080          }
01081 
01082          /* Evaluate expression */        
01083          cp4 = ast_expr(vars);
01084          
01085          ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
01086          
01087          if (cp4) {
01088             length = strlen(cp4);
01089             if (length > count)
01090                length = count;
01091             memcpy(cp2, cp4, length);
01092             count -= length;
01093             cp2 += length;
01094             free(cp4);
01095          }
01096          
01097       } else
01098          break;
01099    }
01100 }
01101 
01102 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
01103         
01104    memset(passdata, 0, datalen);
01105       
01106    /* No variables or expressions in e->data, so why scan it? */
01107    if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
01108       strncpy(passdata, e->data, datalen - 1);
01109       passdata[datalen-1] = '\0';
01110       return;
01111    }
01112    
01113    pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
01114 }                                                     
01115 
01116 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action) 
01117 {
01118    struct ast_exten *e;
01119    struct ast_app *app;
01120    struct ast_switch *sw;
01121    char *data;
01122    int newstack = 0;
01123    int res;
01124    int status = 0;
01125    char *incstack[AST_PBX_MAX_STACK];
01126    char passdata[256];
01127    int stacklen = 0;
01128    char tmp[80];
01129    char tmp2[80];
01130    char tmp3[256];
01131    if (ast_mutex_lock(&conlock)) {
01132       ast_log(LOG_WARNING, "Unable to obtain lock\n");
01133       if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
01134          return 0;
01135       else
01136          return -1;
01137    }
01138    e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
01139    if (e) {
01140       switch(action) {
01141       case HELPER_CANMATCH:
01142          ast_mutex_unlock(&conlock);
01143          return -1;
01144       case HELPER_EXISTS:
01145          ast_mutex_unlock(&conlock);
01146          return -1;
01147       case HELPER_MATCHMORE:
01148          ast_mutex_unlock(&conlock);
01149          return -1;
01150       case HELPER_SPAWN:
01151          newstack++;
01152          /* Fall through */
01153       case HELPER_EXEC:
01154          app = pbx_findapp(e->app);
01155          ast_mutex_unlock(&conlock);
01156          if (app) {
01157             if (c->context != context)
01158                strncpy(c->context, context, sizeof(c->context)-1);
01159             if (c->exten != exten)
01160                strncpy(c->exten, exten, sizeof(c->exten)-1);
01161             c->priority = priority;
01162             pbx_substitute_variables(passdata, sizeof(passdata), c, e);
01163             if (option_debug)
01164                   ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
01165             else if (option_verbose > 2)
01166                   ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
01167                         term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
01168                         term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
01169                         term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
01170                         (newstack ? "in new stack" : "in same stack"));
01171             res = pbx_exec(c, app, passdata, newstack);
01172             return res;
01173          } else {
01174             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
01175             return -1;
01176          }
01177       default:
01178          ast_log(LOG_WARNING, "Huh (%d)?\n", action);       return -1;
01179       }
01180    } else if (sw) {
01181       switch(action) {
01182       case HELPER_CANMATCH:
01183          ast_mutex_unlock(&conlock);
01184          return -1;
01185       case HELPER_EXISTS:
01186          ast_mutex_unlock(&conlock);
01187          return -1;
01188       case HELPER_MATCHMORE:
01189          ast_mutex_unlock(&conlock);
01190          return -1;
01191       case HELPER_SPAWN:
01192          newstack++;
01193          /* Fall through */
01194       case HELPER_EXEC:
01195          ast_mutex_unlock(&conlock);
01196          if (sw->exec)
01197             res = sw->exec(c, context, exten, priority, callerid, newstack, data);
01198          else {
01199             ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
01200             res = -1;
01201          }
01202          return res;
01203       default:
01204          ast_log(LOG_WARNING, "Huh (%d)?\n", action);
01205          return -1;
01206       }
01207    } else {
01208       ast_mutex_unlock(&conlock);
01209       switch(status) {
01210       case STATUS_NO_CONTEXT:
01211          if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
01212             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
01213          break;
01214       case STATUS_NO_EXTENSION:
01215          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01216             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
01217          break;
01218       case STATUS_NO_PRIORITY:
01219          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01220             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
01221          break;
01222       default:
01223          ast_log(LOG_DEBUG, "Shouldn't happen!\n");
01224       }
01225       if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01226          return -1;
01227       else
01228          return 0;
01229    }
01230 
01231 }
01232 
01233 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
01234 {
01235    struct ast_exten *e;
01236    struct ast_switch *sw;
01237    char *data;
01238    int status = 0;
01239    char *incstack[AST_PBX_MAX_STACK];
01240    int stacklen = 0;
01241 
01242    if (ast_mutex_lock(&conlock)) {
01243       ast_log(LOG_WARNING, "Unable to obtain lock\n");
01244       return NULL;
01245    }
01246    e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
01247    ast_mutex_unlock(&conlock);   
01248    return e;
01249 }
01250 
01251 static int ast_extension_state2(struct ast_exten *e)
01252 {
01253     char hint[AST_MAX_EXTENSION] = "";    
01254     char *cur, *rest;
01255     int res = -1;
01256     int allunavailable = 1, allbusy = 1, allfree = 1;
01257     int busy = 0;
01258 
01259     strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
01260     
01261     cur = hint;    
01262     do {
01263    rest = strchr(cur, '&');
01264    if (rest) {
01265        *rest = 0;
01266        rest++;
01267    }
01268    
01269    res = ast_device_state(cur);
01270    switch (res) {
01271     case AST_DEVICE_NOT_INUSE:
01272       allunavailable = 0;
01273       allbusy = 0;
01274       break;
01275     case AST_DEVICE_INUSE:
01276       return AST_EXTENSION_INUSE;
01277     case AST_DEVICE_BUSY:
01278       allunavailable = 0;
01279       allfree = 0;
01280       busy = 1;
01281       break;
01282     case AST_DEVICE_UNAVAILABLE:
01283     case AST_DEVICE_INVALID:
01284       allbusy = 0;
01285       allfree = 0;
01286       break;
01287     default:
01288       allunavailable = 0;
01289       allbusy = 0;
01290       allfree = 0;
01291    }
01292         cur = rest;
01293     } while (cur);
01294 
01295     if (allfree)
01296       return AST_EXTENSION_NOT_INUSE;
01297     if (allbusy)
01298       return AST_EXTENSION_BUSY;
01299     if (allunavailable)
01300       return AST_EXTENSION_UNAVAILABLE;
01301     if (busy) 
01302       return AST_EXTENSION_INUSE;
01303    
01304     return AST_EXTENSION_NOT_INUSE;
01305 }
01306 
01307 
01308 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
01309 {
01310     struct ast_exten *e;
01311 
01312     e = ast_hint_extension(c, context, exten);    
01313     if (!e) 
01314    return -1;
01315 
01316     return ast_extension_state2(e);    
01317 }
01318 
01319 int ast_device_state_changed(const char *fmt, ...) 
01320 {
01321     struct ast_hint *list;
01322     struct ast_state_cb *cblist;
01323     char hint[AST_MAX_EXTENSION];
01324     char device[AST_MAX_EXTENSION];
01325     char *cur, *rest;
01326     int state;
01327     
01328     va_list ap;
01329 
01330     va_start(ap, fmt);
01331     vsnprintf(device, sizeof(device)-1, fmt, ap);
01332     va_end(ap);
01333 
01334     rest = strchr(device, '-');
01335     if (rest) {
01336    *rest = 0;
01337     }
01338         
01339     ast_mutex_lock(&hintlock);
01340 
01341     list = hints;
01342     
01343     while (list) {
01344    
01345    strcpy(hint, ast_get_extension_app(list->exten));
01346    cur = hint;
01347    do {
01348        rest = strchr(cur, '&');
01349        if (rest) {
01350       *rest = 0;
01351       rest++;
01352        }
01353        
01354        if (!strcmp(cur, device)) {
01355        // Found extension execute callbacks 
01356       state = ast_extension_state2(list->exten);
01357       if ((state != -1) && (state != list->laststate)) {
01358           // For general callbacks
01359           cblist = statecbs;
01360           while (cblist) {
01361          cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
01362          cblist = cblist->next;
01363           }
01364           
01365           // For extension callbacks
01366              cblist = list->callbacks;
01367           while (cblist) {
01368          cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
01369          cblist = cblist->next;
01370           }
01371           
01372           list->laststate = state;
01373       }
01374       break;
01375        }
01376        cur = rest;
01377    } while (cur);
01378    
01379    list = list->next;
01380     }
01381 
01382     ast_mutex_unlock(&hintlock);
01383     return 1;
01384 }
01385          
01386 int ast_extension_state_add(char *context, char *exten, 
01387              ast_state_cb_type callback, void *data)
01388 {
01389     struct ast_hint *list;
01390     struct ast_state_cb *cblist;
01391     struct ast_exten *e;
01392 
01393     /* No context and extension add callback to statecbs list */
01394     if (!context && !exten) {
01395    ast_mutex_lock(&hintlock);
01396 
01397    cblist = statecbs;
01398    while (cblist) {
01399        if (cblist->callback == callback) {
01400       cblist->data = data;
01401       ast_mutex_unlock(&hintlock);
01402        }
01403        
01404        cblist = cblist->next;
01405    }
01406    
01407    /* Now inserts the callback */
01408    cblist = malloc(sizeof(struct ast_state_cb));
01409    if (!cblist) {
01410        ast_mutex_unlock(&hintlock);
01411        return -1;
01412    }
01413    memset(cblist, 0, sizeof(struct ast_state_cb));
01414    cblist->id = 0;
01415    cblist->callback = callback;
01416    cblist->data = data;
01417 
01418         cblist->next = statecbs;
01419    statecbs = cblist;
01420 
01421    ast_mutex_unlock(&hintlock);
01422    return 0;
01423     }
01424 
01425     if (!context || !exten)
01426    return -1;
01427 
01428     /* This callback type is for only one hint */
01429     e = ast_hint_extension(NULL, context, exten);    
01430     if (!e) {
01431         return -1;
01432     }
01433     
01434     ast_mutex_lock(&hintlock);
01435     list = hints;        
01436     
01437     while (list) {
01438    if (list->exten == e)
01439        break;      
01440    list = list->next;    
01441     }
01442 
01443     if (!list) {
01444    ast_mutex_unlock(&hintlock);
01445    return -1;
01446     }
01447 
01448     /* Now inserts the callback */
01449     cblist = malloc(sizeof(struct ast_state_cb));
01450     if (!cblist) {
01451    ast_mutex_unlock(&hintlock);
01452    return -1;
01453     }
01454     memset(cblist, 0, sizeof(struct ast_state_cb));
01455     cblist->id = stateid++;
01456     cblist->callback = callback;
01457     cblist->data = data;
01458 
01459     cblist->next = list->callbacks;
01460     list->callbacks = cblist;
01461 
01462     ast_mutex_unlock(&hintlock);
01463     return cblist->id;
01464 }
01465 
01466 int ast_extension_state_del(int id, ast_state_cb_type callback)
01467 {
01468     struct ast_hint *list;
01469     struct ast_state_cb *cblist, *cbprev;
01470     
01471     if (!id && !callback)
01472    return -1;
01473             
01474     ast_mutex_lock(&hintlock);
01475 
01476     /* id is zero is a callback without extension */
01477     if (!id) {
01478    cbprev = NULL;
01479    cblist = statecbs;
01480    while (cblist) {
01481        if (cblist->callback == callback) {
01482       if (!cbprev)
01483           statecbs = cblist->next;
01484       else
01485           cbprev->next = cblist->next;
01486 
01487       free(cblist);
01488 
01489            ast_mutex_unlock(&hintlock);
01490       return 0;
01491        }
01492        cbprev = cblist;
01493        cblist = cblist->next;
01494    }
01495 
01496         ast_mutex_lock(&hintlock);
01497    return -1;
01498     }
01499 
01500     /* id greater zero is a callback with extension */
01501     list = hints;
01502     while (list) {
01503    cblist = list->callbacks;
01504    cbprev = NULL;
01505    while (cblist) {
01506        if (cblist->id==id) {
01507       if (!cbprev)
01508           list->callbacks = cblist->next;    
01509       else
01510           cbprev->next = cblist->next;
01511       
01512       free(cblist);
01513       
01514       ast_mutex_unlock(&hintlock);
01515       return 0;      
01516        }    
01517           cbprev = cblist;          
01518        cblist = cblist->next;
01519    }
01520    list = list->next;
01521     }
01522     
01523     ast_mutex_unlock(&hintlock);
01524     return -1;
01525 }
01526 
01527 static int ast_add_hint(struct ast_exten *e)
01528 {
01529     struct ast_hint *list;
01530 
01531     if (!e) return -1;
01532     
01533     ast_mutex_lock(&hintlock);
01534     list = hints;        
01535     
01536     /* Search if hint exists, do nothing */
01537     while (list) {
01538    if (list->exten == e) {
01539        ast_mutex_unlock(&hintlock);
01540        return -1;
01541    }
01542    list = list->next;    
01543     }
01544 
01545     list = malloc(sizeof(struct ast_hint));
01546     if (!list) {
01547    ast_mutex_unlock(&hintlock);
01548    return -1;
01549     }
01550     /* Initialize and insert new item */
01551     memset(list, 0, sizeof(struct ast_hint));
01552     list->exten = e;
01553     list->laststate = ast_extension_state2(e);
01554     list->next = hints;
01555     hints = list;
01556 
01557     ast_mutex_unlock(&hintlock);
01558     return 0;
01559 }
01560 
01561 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
01562 { 
01563     struct ast_hint *list;
01564 
01565     ast_mutex_lock(&hintlock);
01566     
01567     list = hints;
01568     
01569     while(list) {
01570    if (list->exten == oe) {
01571        list->exten = ne;
01572        ast_mutex_unlock(&hintlock); 
01573        return 0;
01574    }
01575    list = list->next;
01576     }
01577     ast_mutex_unlock(&hintlock);
01578 
01579     return -1;
01580 }
01581 
01582 static int ast_remove_hint(struct ast_exten *e)
01583 {
01584     /* Cleanup the Notifys if hint is removed */
01585     struct ast_hint *list, *prev = NULL;
01586     struct ast_state_cb *cblist, *cbprev;
01587 
01588     if (!e) 
01589    return -1;
01590 
01591     ast_mutex_lock(&hintlock);
01592 
01593     list = hints;    
01594     while(list) {
01595    if (list->exten==e) {
01596        cbprev = NULL;
01597        cblist = list->callbacks;
01598        while (cblist) {
01599       /* Notify with -1 and remove all callbacks */
01600       cbprev = cblist;      
01601       cblist = cblist->next;
01602       cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
01603       free(cbprev);
01604        }
01605        list->callbacks = NULL;
01606 
01607        if (!prev)
01608       hints = list->next;
01609        else
01610       prev->next = list->next;
01611 
01612        free(list);
01613        
01614        ast_mutex_unlock(&hintlock);
01615        return 0;
01616    } else {
01617        prev = list;
01618           list = list->next;    
01619    }
01620     }
01621 
01622     ast_mutex_unlock(&hintlock);
01623     return -1;
01624 }
01625 
01626 
01627 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
01628 {
01629    struct ast_exten *e;
01630    e = ast_hint_extension(c, context, exten);
01631    if (e) { 
01632        strncpy(hint, ast_get_extension_app(e), maxlen);
01633        return -1;
01634    }
01635    return 0;   
01636 }
01637 
01638 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
01639 {
01640    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
01641 }
01642 
01643 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
01644 {
01645    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
01646 }
01647 
01648 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
01649 {
01650    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
01651 }
01652 
01653 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
01654 {
01655    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
01656 }
01657 
01658 int ast_pbx_run(struct ast_channel *c)
01659 {
01660    int firstpass = 1;
01661    char digit;
01662    char exten[256];
01663    int pos;
01664    int waittime;
01665    int res=0;
01666 
01667    /* A little initial setup here */
01668    if (c->pbx)
01669       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
01670    c->pbx = malloc(sizeof(struct ast_pbx));
01671    if (!c->pbx) {
01672       ast_log(LOG_ERROR, "Out of memory\n");
01673       return -1;
01674    }
01675    if (c->amaflags) {
01676       if (c->cdr) {
01677          ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
01678       } else {
01679          c->cdr = ast_cdr_alloc();
01680          if (!c->cdr) {
01681             ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01682             free(c->pbx);
01683             return -1;
01684          }
01685          ast_cdr_init(c->cdr, c);
01686       }
01687    }
01688    memset(c->pbx, 0, sizeof(struct ast_pbx));
01689    /* Set reasonable defaults */
01690    c->pbx->rtimeout = 10;
01691    c->pbx->dtimeout = 5;
01692 
01693    /* Start by trying whatever the channel is set to */
01694    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01695       /* JK02: If not successfull fall back to 's' */
01696       strncpy(c->exten, "s", sizeof(c->exten)-1);
01697       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01698          /* JK02: And finally back to default if everything else failed */
01699          strncpy(c->context, "default", sizeof(c->context)-1);
01700       }
01701       c->priority = 1;
01702    }
01703    if (c->cdr)
01704       ast_cdr_start(c->cdr);
01705    for(;;) {
01706       pos = 0;
01707       digit = 0;
01708       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01709          memset(exten, 0, sizeof(exten));
01710          manager_event(EVENT_FLAG_CALL, "Newexten", 
01711             "Channel: %s\r\n"
01712             "Context: %s\r\n"
01713             "Extension: %s\r\n"
01714             "Priority: %d\r\n"
01715             "Uniqueid: %s\r\n",
01716             c->name, c->context, c->exten, c->priority, c->uniqueid);
01717          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
01718             /* Something bad happened, or a hangup has been requested. */
01719             if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
01720                (res == '*') || (res == '#')) {
01721                ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
01722                memset(exten, 0, sizeof(exten));
01723                pos = 0;
01724                exten[pos++] = digit = res;
01725                break;
01726             }
01727             switch(res) {
01728             case AST_PBX_KEEPALIVE:
01729                if (option_debug)
01730                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
01731                else if (option_verbose > 1)
01732                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
01733                goto out;
01734                break;
01735             default:
01736                if (option_debug)
01737                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01738                else if (option_verbose > 1)
01739                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01740                if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
01741                   c->_softhangup =0;
01742                   break;
01743                }
01744                /* atimeout */
01745                if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
01746                   break;
01747                }
01748 
01749                if (c->cdr) {
01750                   ast_cdr_update(c);
01751                }
01752                goto out;
01753             }
01754          }
01755          if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
01756             strncpy(c->exten,"T",sizeof(c->exten) - 1);
01757             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
01758             c->whentohangup = 0;
01759             c->priority = 0;
01760             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
01761          } else if (c->_softhangup) {
01762             ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
01763                c->exten, c->priority);
01764             goto out;
01765          }
01766          firstpass = 0;
01767          c->priority++;
01768       }
01769       if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
01770          /* It's not a valid extension anymore */
01771          if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
01772             if (option_verbose > 2)
01773                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
01774             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
01775             strncpy(c->exten, "i", sizeof(c->exten)-1);
01776             c->priority = 1;
01777          } else {
01778             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
01779                c->name, c->exten, c->context);
01780             goto out;
01781          }
01782       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
01783          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
01784          c->_softhangup = 0;
01785       } else {
01786          /* Done, wait for an extension */
01787          if (digit)
01788             waittime = c->pbx->dtimeout;
01789          else
01790             waittime = c->pbx->rtimeout;
01791          while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
01792             /* As long as we're willing to wait, and as long as it's not defined, 
01793                keep reading digits until we can't possibly get a right answer anymore.  */
01794             digit = ast_waitfordigit(c, waittime * 1000);
01795             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
01796                c->_softhangup = 0;
01797             } else {
01798                if (!digit)
01799                   /* No entry */
01800                   break;
01801                if (digit < 0)
01802                   /* Error, maybe a  hangup */
01803                   goto out;
01804                exten[pos++] = digit;
01805                waittime = c->pbx->dtimeout;
01806             }
01807          }
01808          if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
01809             /* Prepare the next cycle */
01810             strncpy(c->exten, exten, sizeof(c->exten)-1);
01811             c->priority = 1;
01812          } else {
01813             /* No such extension */
01814             if (strlen(exten)) {
01815                /* An invalid extension */
01816                if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
01817                   if (option_verbose > 2)
01818                      ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
01819                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
01820                   strncpy(c->exten, "i", sizeof(c->exten)-1);
01821                   c->priority = 1;
01822                } else {
01823                   ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
01824                   goto out;
01825                }
01826             } else {
01827                /* A simple timeout */
01828                if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
01829                   if (option_verbose > 2)
01830                      ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
01831                   strncpy(c->exten, "t", sizeof(c->exten)-1);
01832                   c->priority = 1;
01833                } else {
01834                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
01835                   goto out;
01836                }
01837             }  
01838          }
01839          if (c->cdr) {
01840              if (option_verbose > 2)
01841             ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);   
01842              ast_cdr_update(c);
01843           }
01844       }
01845    }
01846    if (firstpass) 
01847       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
01848 out:
01849    if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
01850       strcpy(c->exten, "h");
01851       c->priority = 1;
01852       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01853          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
01854             /* Something bad happened, or a hangup has been requested. */
01855             if (option_debug)
01856                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01857             else if (option_verbose > 1)
01858                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01859             break;
01860          }
01861          c->priority++;
01862       }
01863    }
01864 
01865    pbx_destroy(c->pbx);
01866    c->pbx = NULL;
01867    if (res != AST_PBX_KEEPALIVE)
01868       ast_hangup(c);
01869    return 0;
01870 }
01871 
01872 static void *pbx_thread(void *data)
01873 {
01874    /* Oh joyeous kernel, we're a new thread, with nothing to do but
01875       answer this channel and get it going.  The setjmp stuff is fairly
01876       confusing, but necessary to get smooth transitions between
01877       the execution of different applications (without the use of
01878       additional threads) */
01879    struct ast_channel *c = data;
01880    ast_pbx_run(c);
01881    pthread_exit(NULL);
01882    return NULL;
01883 }
01884 
01885 int ast_pbx_start(struct ast_channel *c)
01886 {
01887    pthread_t t;
01888    pthread_attr_t attr;
01889    if (!c) {
01890       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
01891       return -1;
01892    }
01893       
01894    /* Start a new thread, and get something handling this channel. */
01895    pthread_attr_init(&attr);
01896    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01897    if (pthread_create(&t, &attr, pbx_thread, c)) {
01898       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
01899       return -1;
01900    }
01901    return 0;
01902 }
01903 
01904 /*
01905  * This function locks contexts list by &conlist, search for the rigt context
01906  * structure, leave context list locked and call ast_context_remove_include2
01907  * which removes include, unlock contexts list and return ...
01908  */
01909 int ast_context_remove_include(char *context, char *include, char *registrar)
01910 {
01911    struct ast_context *c;
01912 
01913    if (ast_lock_contexts()) return -1;
01914 
01915    /* walk contexts and search for the right one ...*/
01916    c = ast_walk_contexts(NULL);
01917    while (c) {
01918       /* we found one ... */
01919       if (!strcmp(ast_get_context_name(c), context)) {
01920          int ret;
01921          /* remove include from this context ... */   
01922          ret = ast_context_remove_include2(c, include, registrar);
01923 
01924          ast_unlock_contexts();
01925 
01926          /* ... return results */
01927          return ret;
01928       }
01929       c = ast_walk_contexts(c);
01930    }
01931 
01932    /* we can't find the right one context */
01933    ast_unlock_contexts();
01934    return -1;
01935 }
01936 
01937 /*
01938  * When we call this function, &conlock lock must be locked, because when
01939  * we giving *con argument, some process can remove/change this context
01940  * and after that there can be segfault.
01941  *
01942  * This function locks given context, removes include, unlock context and
01943  * return.
01944  */
01945 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
01946 {
01947    struct ast_include *i, *pi = NULL;
01948 
01949    if (ast_mutex_lock(&con->lock)) return -1;
01950 
01951    /* walk includes */
01952    i = con->includes;
01953    while (i) {
01954       /* find our include */
01955       if (!strcmp(i->name, include) && 
01956          (!strcmp(i->registrar, registrar) || !registrar)) {
01957          /* remove from list */
01958          if (pi)
01959             pi->next = i->next;
01960          else
01961             con->includes = i->next;
01962          /* free include and return */
01963          free(i);
01964          ast_mutex_unlock(&con->lock);
01965          return 0;
01966       }
01967       pi = i;
01968       i = i->next;
01969    }
01970 
01971    /* we can't find the right include */
01972    ast_mutex_unlock(&con->lock);
01973    return -1;
01974 }
01975 
01976 /*
01977  * This function locks contexts list by &conlist, search for the rigt context
01978  * structure, leave context list locked and call ast_context_remove_switch2
01979  * which removes switch, unlock contexts list and return ...
01980  */
01981 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
01982 {
01983    struct ast_context *c;
01984 
01985    if (ast_lock_contexts()) return -1;
01986 
01987    /* walk contexts and search for the right one ...*/
01988    c = ast_walk_contexts(NULL);
01989    while (c) {
01990       /* we found one ... */
01991       if (!strcmp(ast_get_context_name(c), context)) {
01992          int ret;
01993          /* remove switch from this context ... */ 
01994          ret = ast_context_remove_switch2(c, sw, data, registrar);
01995 
01996          ast_unlock_contexts();
01997 
01998          /* ... return results */
01999          return ret;
02000       }
02001       c = ast_walk_contexts(c);
02002    }
02003 
02004    /* we can't find the right one context */
02005    ast_unlock_contexts();
02006    return -1;
02007 }
02008 
02009 /*
02010  * When we call this function, &conlock lock must be locked, because when
02011  * we giving *con argument, some process can remove/change this context
02012  * and after that there can be segfault.
02013  *
02014  * This function locks given context, removes switch, unlock context and
02015  * return.
02016  */
02017 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
02018 {
02019    struct ast_sw *i, *pi = NULL;
02020 
02021    if (ast_mutex_lock(&con->lock)) return -1;
02022 
02023    /* walk switchs */
02024    i = con->alts;
02025    while (i) {
02026       /* find our switch */
02027       if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
02028          (!strcmp(i->registrar, registrar) || !registrar)) {
02029          /* remove from list */
02030          if (pi)
02031             pi->next = i->next;
02032          else
02033             con->alts = i->next;
02034          /* free switch and return */
02035          free(i);
02036          ast_mutex_unlock(&con->lock);
02037          return 0;
02038       }
02039       pi = i;
02040       i = i->next;
02041    }
02042 
02043    /* we can't find the right switch */
02044    ast_mutex_unlock(&con->lock);
02045    return -1;
02046 }
02047 
02048 /*
02049  * This functions lock contexts list, search for the right context,
02050  * call ast_context_remove_extension2, unlock contexts list and return.
02051  * In this function we are using
02052  */
02053 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
02054 {
02055    struct ast_context *c;
02056 
02057    if (ast_lock_contexts()) return -1;
02058 
02059    /* walk contexts ... */
02060    c = ast_walk_contexts(NULL);
02061    while (c) {
02062       /* ... search for the right one ... */
02063       if (!strcmp(ast_get_context_name(c), context)) {
02064          /* ... remove extension ... */
02065          int ret = ast_context_remove_extension2(c, extension, priority,
02066             registrar);
02067          /* ... unlock contexts list and return */
02068          ast_unlock_contexts();
02069          return ret;
02070       }
02071       c = ast_walk_contexts(c);
02072    }
02073 
02074    /* we can't find the right context */
02075    ast_unlock_contexts();
02076    return -1;
02077 }
02078 
02079 /*
02080  * When do you want to call this function, make sure that &conlock is locked,
02081  * because some process can handle with your *con context before you lock
02082  * it.
02083  *
02084  * This functionc locks given context, search for the right extension and
02085  * fires out all peer in this extensions with given priority. If priority
02086  * is set to 0, all peers are removed. After that, unlock context and
02087  * return.
02088  */
02089 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
02090 {
02091    struct ast_exten *exten, *prev_exten = NULL;
02092 
02093    if (ast_mutex_lock(&con->lock)) return -1;
02094 
02095    /* go through all extensions in context and search the right one ... */
02096    exten = con->root;
02097    while (exten) {
02098 
02099       /* look for right extension */
02100       if (!strcmp(exten->exten, extension) &&
02101          (!strcmp(exten->registrar, registrar) || !registrar)) {
02102          struct ast_exten *peer;
02103 
02104          /* should we free all peers in this extension? (priority == 0)? */
02105          if (priority == 0) {
02106             /* remove this extension from context list */
02107             if (prev_exten)
02108                prev_exten->next = exten->next;
02109             else
02110                con->root = exten->next;
02111 
02112             /* fire out all peers */
02113             peer = exten; 
02114             while (peer) {
02115                exten = peer->peer;
02116                
02117                if (!peer->priority==PRIORITY_HINT) 
02118                    ast_remove_hint(peer);
02119 
02120                peer->datad(peer->data);
02121                free(peer);
02122 
02123                peer = exten;
02124             }
02125 
02126             ast_mutex_unlock(&con->lock);
02127             return 0;
02128          } else {
02129             /* remove only extension with exten->priority == priority */
02130             struct ast_exten *previous_peer = NULL;
02131 
02132             peer = exten;
02133             while (peer) {
02134                /* is this our extension? */
02135                if (peer->priority == priority &&
02136                   (!strcmp(peer->registrar, registrar) || !registrar)) {
02137                   /* we are first priority extension? */
02138                   if (!previous_peer) {
02139                      /* exists previous extension here? */
02140                      if (prev_exten) {
02141                         /* yes, so we must change next pointer in
02142                          * previous connection to next peer
02143                          */
02144                         if (peer->peer) {
02145                            prev_exten->next = peer->peer;
02146                            peer->peer->next = exten->next;
02147                         } else
02148                            prev_exten->next = exten->next;
02149                      } else {
02150                         /* no previous extension, we are first
02151                          * extension, so change con->root ...
02152                          */
02153                         if (peer->peer)
02154                            con->root = peer->peer;
02155                         else
02156                            con->root = exten->next; 
02157                      }
02158                   } else {
02159                      /* we are not first priority in extension */
02160                      previous_peer->peer = peer->peer;
02161                   }
02162 
02163                   /* now, free whole priority extension */
02164                   if (peer->priority==PRIORITY_HINT)
02165                       ast_remove_hint(peer);
02166                   peer->datad(peer->data);
02167                   free(peer);
02168 
02169                   ast_mutex_unlock(&con->lock);
02170                   return 0;
02171                } else {
02172                   /* this is not right extension, skip to next peer */
02173                   previous_peer = peer;
02174                   peer = peer->peer;
02175                }
02176             }
02177 
02178             ast_mutex_unlock(&con->lock);
02179             return -1;
02180          }
02181       }
02182 
02183       prev_exten = exten;
02184       exten = exten->next;
02185    }
02186 
02187    /* we can't find right extension */
02188    ast_mutex_unlock(&con->lock);
02189    return -1;
02190 }
02191 
02192 
02193 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
02194 {
02195    struct ast_app *tmp, *prev, *cur;
02196    char tmps[80];
02197    if (ast_mutex_lock(&applock)) {
02198       ast_log(LOG_ERROR, "Unable to lock application list\n");
02199       return -1;
02200    }
02201    tmp = apps;
02202    while(tmp) {
02203       if (!strcasecmp(app, tmp->name)) {
02204          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02205          ast_mutex_unlock(&applock);
02206          return -1;
02207       }
02208       tmp = tmp->next;
02209    }
02210    tmp = malloc(sizeof(struct ast_app));
02211    if (tmp) {
02212       memset(tmp, 0, sizeof(struct ast_app));
02213       strncpy(tmp->name, app, sizeof(tmp->name)-1);
02214       tmp->execute = execute;
02215       tmp->synopsis = synopsis;
02216       tmp->description = description;
02217       /* Store in alphabetical order */
02218       cur = apps;
02219       prev = NULL;
02220       while(cur) {
02221          if (strcasecmp(tmp->name, cur->name) < 0)
02222             break;
02223          prev = cur;
02224          cur = cur->next;
02225       }
02226       if (prev) {
02227          tmp->next = prev->next;
02228          prev->next = tmp;
02229       } else {
02230          tmp->next = apps;
02231          apps = tmp;
02232       }
02233    } else {
02234       ast_log(LOG_ERROR, "Out of memory\n");
02235       ast_mutex_unlock(&applock);
02236       return -1;
02237    }
02238    if (option_verbose > 1)
02239       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02240    ast_mutex_unlock(&applock);
02241    return 0;
02242 }
02243 
02244 int ast_register_switch(struct ast_switch *sw)
02245 {
02246    struct ast_switch *tmp, *prev=NULL;
02247    if (ast_mutex_lock(&switchlock)) {
02248       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02249       return -1;
02250    }
02251    tmp = switches;
02252    while(tmp) {
02253       if (!strcasecmp(tmp->name, sw->name))
02254          break;
02255       prev = tmp;
02256       tmp = tmp->next;
02257    }
02258    if (tmp) {  
02259       ast_mutex_unlock(&switchlock);
02260       ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
02261       return -1;
02262    }
02263    sw->next = NULL;
02264    if (prev) 
02265       prev->next = sw;
02266    else
02267       switches = sw;
02268    ast_mutex_unlock(&switchlock);
02269    return 0;
02270 }
02271 
02272 void ast_unregister_switch(struct ast_switch *sw)
02273 {
02274    struct ast_switch *tmp, *prev=NULL;
02275    if (ast_mutex_lock(&switchlock)) {
02276       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02277       return;
02278    }
02279    tmp = switches;
02280    while(tmp) {
02281       if (tmp == sw) {
02282          if (prev)
02283             prev->next = tmp->next;
02284          else
02285             switches = tmp->next;
02286          tmp->next = NULL;
02287          break;         
02288       }
02289       prev = tmp;
02290       tmp = tmp->next;
02291    }
02292    ast_mutex_unlock(&switchlock);
02293 }
02294 
02295 /*
02296  * Help for CLI commands ...
02297  */
02298 static char show_application_help[] = 
02299 "Usage: show application <application> [<application> [<application> [...]]]\n"
02300 "       Describes a particular application.\n";
02301 
02302 static char show_applications_help[] =
02303 "Usage: show applications\n"
02304 "       List applications which are currently available.\n";
02305 
02306 static char show_dialplan_help[] =
02307 "Usage: show dialplan [exten@][context]\n"
02308 "       Show dialplan\n";
02309 
02310 static char show_switches_help[] = 
02311 "Usage: show switches\n"
02312 "       Show registered switches\n";
02313 
02314 /*
02315  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
02316  *
02317  */
02318 
02319 /*
02320  * 'show application' CLI command implementation functions ...
02321  */
02322 
02323 /*
02324  * There is a possibility to show informations about more than one
02325  * application at one time. You can type 'show application Dial Echo' and
02326  * you will see informations about these two applications ...
02327  */
02328 static char *complete_show_application(char *line, char *word,
02329    int pos, int state)
02330 {
02331    struct ast_app *a;
02332    int which = 0;
02333 
02334    /* try to lock applications list ... */
02335    if (ast_mutex_lock(&applock)) {
02336       ast_log(LOG_ERROR, "Unable to lock application list\n");
02337       return NULL;
02338    }
02339 
02340    /* ... walk all applications ... */
02341    a = apps; 
02342    while (a) {
02343       /* ... check if word matches this application ... */
02344       if (!strncasecmp(word, a->name, strlen(word))) {
02345          /* ... if this is right app serve it ... */
02346          if (++which > state) {
02347             char *ret = strdup(a->name);
02348             ast_mutex_unlock(&applock);
02349             return ret;
02350          }
02351       }
02352       a = a->next; 
02353    }
02354 
02355    /* no application match */
02356    ast_mutex_unlock(&applock);
02357    return NULL; 
02358 }
02359 
02360 static int handle_show_application(int fd, int argc, char *argv[])
02361 {
02362    struct ast_app *a;
02363    int app, no_registered_app = 1;
02364 
02365    if (argc < 3) return RESULT_SHOWUSAGE;
02366 
02367    /* try to lock applications list ... */
02368    if (ast_mutex_lock(&applock)) {
02369       ast_log(LOG_ERROR, "Unable to lock application list\n");
02370       return -1;
02371    }
02372 
02373    /* ... go through all applications ... */
02374    a = apps; 
02375    while (a) {
02376       /* ... compare this application name with all arguments given
02377        * to 'show application' command ... */
02378       for (app = 2; app < argc; app++) {
02379          if (!strcasecmp(a->name, argv[app])) {
02380             /* Maximum number of characters added by terminal coloring is 22 */
02381             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02382             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02383             int synopsis_size, description_size;
02384 
02385             no_registered_app = 0;
02386 
02387             if (a->synopsis)
02388                synopsis_size = strlen(a->synopsis) + 23;
02389             else
02390                synopsis_size = strlen("Not available") + 23;
02391             synopsis = alloca(synopsis_size);
02392 
02393             if (a->description)
02394                description_size = strlen(a->description) + 23;
02395             else
02396                description_size = strlen("Not available") + 23;
02397             description = alloca(description_size);
02398 
02399             if (synopsis && description) {
02400                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
02401                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02402                term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
02403                term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
02404                term_color(synopsis,
02405                            a->synopsis ? a->synopsis : "Not available",
02406                            COLOR_CYAN, 0, synopsis_size);
02407                term_color(description,
02408                            a->description ? a->description : "Not available",
02409                            COLOR_CYAN, 0, description_size);
02410 
02411                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
02412             } else {
02413                /* ... one of our applications, show info ...*/
02414                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
02415                   "[Synopsis]:\n  %s\n\n"
02416                   "[Description]:\n%s\n",
02417                   a->name,
02418                   a->synopsis ? a->synopsis : "Not available",
02419                   a->description ? a->description : "Not available");
02420             }
02421          }
02422       }
02423       a = a->next; 
02424    }
02425 
02426    ast_mutex_unlock(&applock);
02427 
02428    /* we found at least one app? no? */
02429    if (no_registered_app) {
02430       ast_cli(fd, "Your application(s) is (are) not registered\n");
02431       return RESULT_FAILURE;
02432    }
02433 
02434    return RESULT_SUCCESS;
02435 }
02436 
02437 static int handle_show_switches(int fd, int argc, char *argv[])
02438 {
02439    struct ast_switch *sw;
02440    if (!switches) {
02441       ast_cli(fd, "There are no registered alternative switches\n");
02442       return RESULT_SUCCESS;
02443    }
02444    /* ... we have applications ... */
02445    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
02446    if (ast_mutex_lock(&switchlock)) {
02447       ast_log(LOG_ERROR, "Unable to lock switches\n");
02448       return -1;
02449    }
02450    sw = switches;
02451    while (sw) {
02452       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
02453       sw = sw->next;
02454    }
02455    ast_mutex_unlock(&switchlock);
02456    return RESULT_SUCCESS;
02457 }
02458 
02459 /*
02460  * 'show applications' CLI command implementation functions ...
02461  */
02462 static int handle_show_applications(int fd, int argc, char *argv[])
02463 {
02464    struct ast_app *a;
02465 
02466    /* try to lock applications list ... */
02467    if (ast_mutex_lock(&applock)) {
02468       ast_log(LOG_ERROR, "Unable to lock application list\n");
02469       return -1;
02470    }
02471 
02472    /* ... go to first application ... */
02473    a = apps; 
02474 
02475    /* ... have we got at least one application (first)? no? */
02476    if (!a) {
02477       ast_cli(fd, "There is no registered applications\n");
02478       ast_mutex_unlock(&applock);
02479       return -1;
02480    }
02481 
02482    /* ... we have applications ... */
02483    ast_cli(fd, "\n    -= Registered Asterisk Applications =-\n");
02484 
02485    /* ... go through all applications ... */
02486    while (a) {
02487       /* ... show informations about applications ... */
02488       ast_cli(fd,"  %20s: %s\n",
02489          a->name,
02490          a->synopsis ? a->synopsis : "<Synopsis not available>");
02491       a = a->next; 
02492    }
02493 
02494    /* ... unlock and return */
02495    ast_mutex_unlock(&applock);
02496 
02497    return RESULT_SUCCESS;
02498 }
02499 
02500 /*
02501  * 'show dialplan' CLI command implementation functions ...
02502  */
02503 static char *complete_show_dialplan_context(char *line, char *word, int pos,
02504    int state)
02505 {
02506    struct ast_context *c;
02507    int which = 0;
02508 
02509    /* we are do completion of [exten@]context on second position only */
02510    if (pos != 2) return NULL;
02511 
02512    /* try to lock contexts list ... */
02513    if (ast_lock_contexts()) {
02514       ast_log(LOG_ERROR, "Unable to lock context list\n");
02515       return NULL;
02516    }
02517 
02518    /* ... walk through all contexts ... */
02519    c = ast_walk_contexts(NULL);
02520    while(c) {
02521       /* ... word matches context name? yes? ... */
02522       if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
02523          /* ... for serve? ... */
02524          if (++which > state) {
02525             /* ... yes, serve this context name ... */
02526             char *ret = strdup(ast_get_context_name(c));
02527             ast_unlock_contexts();
02528             return ret;
02529          }
02530       }
02531       c = ast_walk_contexts(c);
02532    }
02533 
02534    /* ... unlock and return */
02535    ast_unlock_contexts();
02536    return NULL;
02537 }
02538 
02539 static int handle_show_dialplan(int fd, int argc, char *argv[])
02540 {
02541    struct ast_context *c;
02542    char *exten = NULL, *context = NULL;
02543    int context_existence = 0, extension_existence = 0;
02544 
02545    if (argc != 3 && argc != 2) return -1;
02546 
02547    /* we obtain [exten@]context? if yes, split them ... */
02548    if (argc == 3) {
02549       char *splitter = argv[2];
02550       /* is there a '@' character? */
02551       if (strchr(argv[2], '@')) {
02552          /* yes, split into exten & context ... */
02553          exten   = strsep(&splitter, "@");
         context = splitter;

         /* check for length and change to NULL if !strlen() */
         if (!strlen(exten))   exten = NULL;
         if (!strlen(context)) context = NULL;
      } else
      {
         /* no '@' char, only context given */
         context = argv[2];
         if (!strlen(context)) context = NULL;
      }
   }

   /* try to lock contexts */
   if (ast_lock_contexts()) {
      ast_log(LOG_WARNING, "Failed to lock contexts list\n");
02554       return RESULT_FAILURE;
02555    }
02556 
02557    /* walk all contexts ... */
02558    c = ast_walk_contexts(NULL);
02559    while (c) {
02560       /* show this context? */
02561       if (!context ||
02562          !strcmp(ast_get_context_name(c), context)) {
02563          context_existence = 1;
02564 
02565          /* try to lock context before walking in ... */
02566          if (!ast_lock_context(c)) {
02567             struct ast_exten *e;
02568             struct ast_include *i;
02569             struct ast_ignorepat *ip;
02570             struct ast_sw *sw;
02571             char buf[256], buf2[256];
02572             int context_info_printed = 0;
02573 
02574             /* are we looking for exten too? if yes, we print context
02575              * if we our extension only
02576              */
02577             if (!exten) {
02578                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
02579                   ast_get_context_name(c), ast_get_context_registrar(c));
02580                context_info_printed = 1;
02581             }
02582 
02583             /* walk extensions ... */
02584             e = ast_walk_context_extensions(c, NULL);
02585             while (e) {
02586                struct ast_exten *p;
02587 
02588                /* looking for extension? is this our extension? */
02589                if (exten &&
02590                   strcmp(ast_get_extension_name(e), exten))
02591                {
02592                   /* we are looking for extension and it's not our
02593                    * extension, so skip to next extension */
02594                   e = ast_walk_context_extensions(c, e);
02595                   continue;
02596                }
02597 
02598                extension_existence = 1;
02599 
02600                /* may we print context info? */ 
02601                if (!context_info_printed) {
02602                   ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
02603                      ast_get_context_name(c),
02604                      ast_get_context_registrar(c));
02605                   context_info_printed = 1;
02606                }
02607 
02608                /* write extension name and first peer */ 
02609                bzero(buf, sizeof(buf));      
02610                snprintf(buf, sizeof(buf), "'%s' =>",
02611                   ast_get_extension_name(e));
02612 
02613                snprintf(buf2, sizeof(buf2),
02614                   "%d. %s(%s)",
02615                   ast_get_extension_priority(e),
02616                   ast_get_extension_app(e),
02617                   (char *)ast_get_extension_app_data(e));
02618 
02619                ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
02620                   ast_get_extension_registrar(e));
02621 
02622                /* walk next extension peers */
02623                p = ast_walk_extension_priorities(e, e);
02624                while (p) {
02625                   bzero((void *)buf2, sizeof(buf2));
02626 
02627                   snprintf(buf2, sizeof(buf2),
02628                      "%d. %s(%s)",
02629                      ast_get_extension_priority(p),
02630                      ast_get_extension_app(p),
02631                      (char *)ast_get_extension_app_data(p));
02632 
02633                   ast_cli(fd,"  %-17s %-45s [%s]\n",
02634                      "", buf2,
02635                      ast_get_extension_registrar(p)); 
02636 
02637                   p = ast_walk_extension_priorities(e, p);
02638                }
02639                e = ast_walk_context_extensions(c, e);
02640             }
02641 
02642             /* include & ignorepat we all printing if we are not
02643              * looking for exact extension
02644              */
02645             if (!exten) {
02646                if (ast_walk_context_extensions(c, NULL))
02647                   ast_cli(fd, "\n");
02648 
02649                /* walk included and write info ... */
02650                i = ast_walk_context_includes(c, NULL);
02651                while (i) {
02652                   bzero(buf, sizeof(buf));
02653                   snprintf(buf, sizeof(buf), "'%s'",
02654                      ast_get_include_name(i));
02655                   ast_cli(fd, "  Include =>        %-45s [%s]\n",
02656                      buf, ast_get_include_registrar(i));
02657                   i = ast_walk_context_includes(c, i);
02658                }
02659 
02660                /* walk ignore patterns and write info ... */
02661                ip = ast_walk_context_ignorepats(c, NULL);
02662                while (ip) {
02663                   bzero(buf, sizeof(buf));
02664                   snprintf(buf, sizeof(buf), "'%s'",
02665                      ast_get_ignorepat_name(ip));
02666                   ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
02667                      buf, ast_get_ignorepat_registrar(ip)); 
02668                   ip = ast_walk_context_ignorepats(c, ip);
02669                }
02670                sw = ast_walk_context_switches(c, NULL);
02671                while(sw) {
02672                   bzero(buf, sizeof(buf));
02673                   snprintf(buf, sizeof(buf), "'%s/%s'",
02674                      ast_get_switch_name(sw),
02675                      ast_get_switch_data(sw));
02676                   ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
02677                      buf, ast_get_switch_registrar(sw)); 
02678                   sw = ast_walk_context_switches(c, sw);
02679                }
02680             }
02681    
02682             ast_unlock_context(c);
02683 
02684             /* if we print something in context, make an empty line */
02685             if (context_info_printed) ast_cli(fd, "\n");
02686          }
02687       }
02688       c = ast_walk_contexts(c);
02689    }
02690    ast_unlock_contexts();
02691 
02692    /* check for input failure and throw some error messages */
02693    if (context && !context_existence) {
02694       ast_cli(fd, "There is no existence of '%s' context\n",
02695          context);
02696       return RESULT_FAILURE;
02697    }
02698 
02699    if (exten && !extension_existence) {
02700       if (context)
02701          ast_cli(fd, "There is no existence of %s@%s extension\n",
02702             exten, context);
02703       else
02704          ast_cli(fd,
02705             "There is no existence of '%s' extension in all contexts\n",
02706             exten);
02707       return RESULT_FAILURE;
02708    }
02709 
02710    /* everything ok */
02711    return RESULT_SUCCESS;
02712 }
02713 
02714 /*
02715  * CLI entries for upper commands ...
02716  */
02717 static struct ast_cli_entry show_applications_cli = 
02718    { { "show", "applications", NULL }, 
02719    handle_show_applications, "Shows registered applications",
02720    show_applications_help };
02721 
02722 static struct ast_cli_entry show_application_cli =
02723    { { "show", "application", NULL }, 
02724    handle_show_application, "Describe a specific application",
02725    show_application_help, complete_show_application };
02726 
02727 static struct ast_cli_entry show_dialplan_cli =
02728    { { "show", "dialplan", NULL },
02729       handle_show_dialplan, "Show dialplan",
02730       show_dialplan_help, complete_show_dialplan_context };
02731 
02732 static struct ast_cli_entry show_switches_cli =
02733    { { "show", "switches", NULL },
02734       handle_show_switches, "Show alternative switches",
02735       show_switches_help, NULL };
02736 
02737 int ast_unregister_application(char *app) {
02738    struct ast_app *tmp, *tmpl = NULL;
02739    if (ast_mutex_lock(&applock)) {
02740       ast_log(LOG_ERROR, "Unable to lock application list\n");
02741       return -1;
02742    }
02743    tmp = apps;
02744    while(tmp) {
02745       if (!strcasecmp(app, tmp->name)) {
02746          if (tmpl)
02747             tmpl->next = tmp->next;
02748          else
02749             apps = tmp->next;
02750          if (option_verbose > 1)
02751             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
02752          ast_mutex_unlock(&applock);
02753          return 0;
02754       }
02755       tmpl = tmp;
02756       tmp = tmp->next;
02757    }
02758    ast_mutex_unlock(&applock);
02759    return -1;
02760 }
02761 
02762 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
02763 {
02764    struct ast_context *tmp, **local_contexts;
02765    if (!extcontexts) {
02766       local_contexts = &contexts;
02767       ast_mutex_lock(&conlock);
02768    } else
02769       local_contexts = extcontexts;
02770 
02771    tmp = *local_contexts;
02772    while(tmp) {
02773       if (!strcasecmp(tmp->name, name)) {
02774          ast_mutex_unlock(&conlock);
02775          ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
02776          if (!extcontexts)
02777             ast_mutex_unlock(&conlock);
02778          return NULL;
02779       }
02780       tmp = tmp->next;
02781    }
02782    tmp = malloc(sizeof(struct ast_context));
02783    if (tmp) {
02784       memset(tmp, 0, sizeof(struct ast_context));
02785       ast_mutex_init(&tmp->lock);
02786       strncpy(tmp->name, name, sizeof(tmp->name)-1);
02787       tmp->root = NULL;
02788       tmp->registrar = registrar;
02789       tmp->next = *local_contexts;
02790       tmp->includes = NULL;
02791       tmp->ignorepats = NULL;
02792       *local_contexts = tmp;
02793       if (option_debug)
02794          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
02795       else if (option_verbose > 2)
02796          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
02797    } else
02798       ast_log(LOG_ERROR, "Out of memory\n");
02799    
02800    if (!extcontexts)
02801       ast_mutex_unlock(&conlock);
02802    return tmp;
02803 }
02804 
02805 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
02806 
02807 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
02808    struct ast_context *tmp, *lasttmp = NULL;
02809    tmp = *extcontexts;
02810    ast_mutex_lock(&conlock);
02811    if (registrar) {
02812       __ast_context_destroy(NULL,registrar,0);
02813       while (tmp) {
02814          lasttmp = tmp;
02815          tmp = tmp->next;
02816       }
02817    } else {
02818       while (tmp) {
02819          __ast_context_destroy(tmp,tmp->registrar,0);
02820          lasttmp = tmp;
02821          tmp = tmp->next;
02822       }
02823    }
02824    if (lasttmp) {
02825       lasttmp->next = contexts;
02826       contexts = *extcontexts;
02827       *extcontexts = NULL;
02828    } else 
02829       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
02830    ast_mutex_unlock(&conlock);
02831    return;  
02832 }
02833 
02834 /*
02835  * errno values
02836  *  EBUSY  - can't lock
02837  *  ENOENT - no existence of context
02838  */
02839 int ast_context_add_include(char *context, char *include, char *registrar)
02840 {
02841    struct ast_context *c;
02842 
02843    if (ast_lock_contexts()) {
02844       errno = EBUSY;
02845       return -1;
02846    }
02847 
02848    /* walk contexts ... */
02849    c = ast_walk_contexts(NULL);
02850    while (c) {
02851       /* ... search for the right one ... */
02852       if (!strcmp(ast_get_context_name(c), context)) {
02853          int ret = ast_context_add_include2(c, include, registrar);
02854          /* ... unlock contexts list and return */
02855          ast_unlock_contexts();
02856          return ret;
02857       }
02858       c = ast_walk_contexts(c);
02859    }
02860 
02861    /* we can't find the right context */
02862    ast_unlock_contexts();
02863    errno = ENOENT;
02864    return -1;
02865 }
02866 
02867 #define FIND_NEXT \
02868 do { \
02869    c = info; \
02870    while(*c && (*c != '|')) c++; \
02871    if (*c) { *c = '\0'; c++; } else c = NULL; \
02872 } while(0)
02873 
02874 static void get_timerange(struct ast_include *i, char *times)
02875 {
02876    char *e;
02877    int x;
02878    int s1, s2;
02879    int e1, e2;
02880 // int cth, ctm;
02881 
02882    //[PHM 07/01/03]
02883    //start disabling all times, fill the fields with 0's, as they may contain garbage
02884    memset(i->minmask, 0, sizeof(i->minmask));
02885    
02886    /* Star is all times */
02887    if (!strlen(times) || !strcmp(times, "*")) {
02888       for (x=0;x<24;x++)
02889          i->minmask[x] = (1 << 30) - 1;
02890       return;
02891    }
02892    /* Otherwise expect a range */
02893    e = strchr(times, '-');
02894    if (!e) {
02895       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
02896       return;
02897    }
02898    *e = '\0';
02899    e++;
02900    while(*e && !isdigit(*e)) e++;
02901    if (!*e) {
02902       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
02903       return;
02904    }
02905    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
02906       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
02907       return;
02908    }
02909    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
02910       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
02911       return;
02912    }
02913 
02914 #if 1
02915    s1 = s1 * 30 + s2/2;
02916    if ((s1 < 0) || (s1 >= 24*30)) {
02917       ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
02918       return;
02919    }
02920    e1 = e1 * 30 + e2/2;
02921    if ((e1 < 0) || (e2 >= 24*30)) {
02922       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
02923       return;
02924    }
02925    /* Go through the time and enable each appropriate bit */
02926    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
02927       i->minmask[x/30] |= (1 << (x % 30));
02928    }
02929    /* Do the last one */
02930    i->minmask[x/30] |= (1 << (x % 30));
02931 #else
02932    for (cth=0;cth<24;cth++) {
02933       /* Initialize masks to blank */
02934       i->minmask[cth] = 0;
02935       for (ctm=0;ctm<30;ctm++) {
02936          if (
02937          /* First hour with more than one hour */
02938                (((cth == s1) && (ctm >= s2)) &&
02939                 ((cth < e1)))
02940          /* Only one hour */
02941          ||    (((cth == s1) && (ctm >= s2)) &&
02942                 ((cth == e1) && (ctm <= e2)))
02943          /* In between first and last hours (more than 2 hours) */
02944          ||    ((cth > s1) &&
02945                 (cth < e1))
02946          /* Last hour with more than one hour */
02947          ||    ((cth > s1) &&
02948                 ((cth == e1) && (ctm <= e2)))
02949          )
02950             i->minmask[cth] |= (1 << (ctm / 2));
02951       }
02952    }
02953 #endif
02954    /* All done */
02955    return;
02956 }
02957 
02958 static char *days[] =
02959 {
02960    "sun",
02961    "mon",
02962    "tue",
02963    "wed",
02964    "thu",
02965    "fri",
02966    "sat",
02967 };
02968 
02969 static unsigned int get_dow(char *dow)
02970 {
02971    char *c;
02972    /* The following line is coincidence, really! */
02973    int s, e, x;
02974    unsigned int mask;
02975    /* Check for all days */
02976    if (!strlen(dow) || !strcmp(dow, "*"))
02977       return (1 << 7) - 1;
02978    /* Get start and ending days */
02979    c = strchr(dow, '-');
02980    if (c) {
02981       *c = '\0';
02982       c++;
02983    } else
02984       c = NULL;
02985    /* Find the start */
02986    s = 0;
02987    while((s < 7) && strcasecmp(dow, days[s])) s++;
02988    if (s >= 7) {
02989       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
02990       return 0;
02991    }
02992    if (c) {
02993       e = 0;
02994       while((e < 7) && strcasecmp(c, days[e])) e++;
02995       if (e >= 7) {
02996          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
02997          return 0;
02998       }
02999    } else
03000       e = s;
03001    mask = 0;
03002    for (x=s;x!=e;x = (x + 1) % 7) {
03003       mask |= (1 << x);
03004    }
03005    /* One last one */
03006    mask |= (1 << x);
03007    return mask;
03008 }
03009 
03010 static unsigned int get_day(char *day)
03011 {
03012    char *c;
03013    /* The following line is coincidence, really! */
03014    int s, e, x;
03015    unsigned int mask;
03016    /* Check for all days */
03017    if (!strlen(day) || !strcmp(day, "*")) {
03018       mask = (1 << 30)  + ((1 << 30) - 1);
03019       return mask;
03020    }
03021    /* Get start and ending days */
03022    c = strchr(day, '-');
03023    if (c) {
03024       *c = '\0';
03025       c++;
03026    }
03027    /* Find the start */
03028    if (sscanf(day, "%d", &s) != 1) {
03029       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
03030       return 0;
03031    }
03032    if ((s < 1) || (s > 31)) {
03033       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
03034       return 0;
03035    }
03036    s--;
03037    if (c) {
03038       if (sscanf(c, "%d", &e) != 1) {
03039          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
03040          return 0;
03041       }
03042       if ((e < 1) || (e > 31)) {
03043          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
03044          return 0;
03045       }
03046       e--;
03047    } else
03048       e = s;
03049    mask = 0;
03050    for (x=s;x!=e;x = (x + 1) % 31) {
03051       mask |= (1 << x);
03052    }
03053    mask |= (1 << x);
03054    return mask;
03055 }
03056 
03057 static char *months[] =
03058 {
03059    "jan",
03060    "feb",
03061    "mar",
03062    "apr",
03063    "may",
03064    "jun",
03065    "jul",
03066    "aug",
03067    "sep",
03068    "oct",
03069    "nov",
03070    "dec",
03071 };
03072 
03073 static unsigned int get_month(char *mon)
03074 {
03075    char *c;
03076    /* The following line is coincidence, really! */
03077    int s, e, x;
03078    unsigned int mask;
03079    /* Check for all days */
03080    if (!strlen(mon) || !strcmp(mon, "*")) 
03081       return (1 << 12) - 1;
03082    /* Get start and ending days */
03083    c = strchr(mon, '-');
03084    if (c) {
03085       *c = '\0';
03086       c++;
03087    }
03088    /* Find the start */
03089    s = 0;
03090    while((s < 12) && strcasecmp(mon, months[s])) s++;
03091    if (s >= 12) {
03092       ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
03093       return 0;
03094    }
03095    if (c) {
03096       e = 0;
03097       while((e < 12) && strcasecmp(mon, months[e])) e++;
03098       if (e >= 12) {
03099          ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
03100          return 0;
03101       }
03102    } else
03103       e = s;
03104    mask = 0;
03105    for (x=s;x!=e;x = (x + 1) % 12) {
03106       mask |= (1 << x);
03107    }
03108    /* One last one */
03109    mask |= (1 << x);
03110    return mask;
03111 }
03112 
03113 static void build_timing(struct ast_include *i, char *info)
03114 {
03115    char *c;
03116    /* Check for empty just in case */
03117    if (!strlen(info))
03118       return;
03119    i->hastime = 1;
03120    /* Assume everything except time */
03121    i->monthmask = (1 << 12) - 1;
03122    i->daymask = (1 << 30) - 1 + (1 << 30);
03123    i->dowmask = (1 << 7) - 1;
03124    /* Avoid using str tok */
03125    FIND_NEXT;
03126    /* Info has the time range, start with that */
03127    get_timerange(i, info);
03128    info = c;
03129    if (!info)
03130       return;
03131    FIND_NEXT;
03132    /* Now check for day of week */
03133    i->dowmask = get_dow(info);
03134 
03135    info = c;
03136    if (!info)
03137       return;
03138    FIND_NEXT;
03139    /* Now check for the day of the month */
03140    i->daymask = get_day(info);
03141    info = c;
03142    if (!info)
03143       return;
03144    FIND_NEXT;
03145    /* And finally go for the month */
03146    i->monthmask = get_month(info);
03147 }
03148 
03149 /*
03150  * errno values
03151  *  ENOMEM - out of memory
03152  *  EBUSY  - can't lock
03153  *  EEXIST - already included
03154  *  EINVAL - there is no existence of context for inclusion
03155  */
03156 int ast_context_add_include2(struct ast_context *con, char *value,
03157    char *registrar)
03158 {
03159    struct ast_include *new_include;
03160    char *c;
03161    struct ast_include *i, *il = NULL; /* include, include_last */
03162 
03163    /* allocate new include structure ... */
03164    if (!(new_include = malloc(sizeof(struct ast_include)))) {
03165       ast_log(LOG_ERROR, "Out of memory\n");
03166       errno = ENOMEM;
03167       return -1;
03168    }
03169    
03170    /* ... fill in this structure ... */
03171    memset(new_include, 0, sizeof(struct ast_include));
03172    strncpy(new_include->name, value, sizeof(new_include->name)-1);
03173    strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
03174    c = new_include->rname;
03175    /* Strip off timing info */
03176    while(*c && (*c != '|')) c++; 
03177    /* Process if it's there */
03178    if (*c) {
03179       build_timing(new_include, c+1);
03180       *c = '\0';
03181    }
03182    new_include->next      = NULL;
03183    new_include->registrar = registrar;
03184 
03185    /* ... try to lock this context ... */
03186    if (ast_mutex_lock(&con->lock)) {
03187       free(new_include);
03188       errno = EBUSY;
03189       return -1;
03190    }
03191 
03192    /* ... go to last include and check if context is already included too... */
03193    i = con->includes;
03194    while (i) {
03195       if (!strcasecmp(i->name, new_include->name)) {
03196          free(new_include);
03197          ast_mutex_unlock(&con->lock);
03198          errno = EEXIST;
03199          return -1;
03200       }
03201       il = i;
03202       i = i->next;
03203    }
03204 
03205    /* ... include new context into context list, unlock, return */
03206    if (il)
03207       il->next = new_include;
03208    else
03209       con->includes = new_include;
03210    if (option_verbose > 2)
03211       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 
03212    ast_mutex_unlock(&con->lock);
03213 
03214    return 0;
03215 }
03216 
03217 /*
03218  * errno values
03219  *  EBUSY  - can't lock
03220  *  ENOENT - no existence of context
03221  */
03222 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
03223 {
03224    struct ast_context *c;
03225 
03226    if (ast_lock_contexts()) {
03227       errno = EBUSY;
03228       return -1;
03229    }
03230 
03231    /* walk contexts ... */
03232    c = ast_walk_contexts(NULL);
03233    while (c) {
03234       /* ... search for the right one ... */
03235       if (!strcmp(ast_get_context_name(c), context)) {
03236          int ret = ast_context_add_switch2(c, sw, data, registrar);
03237          /* ... unlock contexts list and return */
03238          ast_unlock_contexts();
03239          return ret;
03240       }
03241       c = ast_walk_contexts(c);
03242    }
03243 
03244    /* we can't find the right context */
03245    ast_unlock_contexts();
03246    errno = ENOENT;
03247    return -1;
03248 }
03249 
03250 /*
03251  * errno values
03252  *  ENOMEM - out of memory
03253  *  EBUSY  - can't lock
03254  *  EEXIST - already included
03255  *  EINVAL - there is no existence of context for inclusion
03256  */
03257 int ast_context_add_switch2(struct ast_context *con, char *value,
03258    char *data, char *registrar)
03259 {
03260    struct ast_sw *new_sw;
03261    struct ast_sw *i, *il = NULL; /* sw, sw_last */
03262 
03263    /* allocate new sw structure ... */
03264    if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
03265       ast_log(LOG_ERROR, "Out of memory\n");
03266       errno = ENOMEM;
03267       return -1;
03268    }
03269    
03270    /* ... fill in this structure ... */
03271    memset(new_sw, 0, sizeof(struct ast_sw));
03272    strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
03273    if (data)
03274       strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
03275    else
03276       strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
03277    new_sw->next      = NULL;
03278    new_sw->registrar = registrar;
03279 
03280    /* ... try to lock this context ... */
03281    if (ast_mutex_lock(&con->lock)) {
03282       free(new_sw);
03283       errno = EBUSY;
03284       return -1;
03285    }
03286 
03287    /* ... go to last sw and check if context is already swd too... */
03288    i = con->alts;
03289    while (i) {
03290       if (!strcasecmp(i->name, new_sw->name)) {
03291          free(new_sw);
03292          ast_mutex_unlock(&con->lock);
03293          errno = EEXIST;
03294          return -1;
03295       }
03296       il = i;
03297       i = i->next;
03298    }
03299 
03300    /* ... sw new context into context list, unlock, return */
03301    if (il)
03302       il->next = new_sw;
03303    else
03304       con->alts = new_sw;
03305    if (option_verbose > 2)
03306       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 
03307    ast_mutex_unlock(&con->lock);
03308 
03309    return 0;
03310 }
03311 
03312 /*
03313  * EBUSY  - can't lock
03314  * ENOENT - there is not context existence
03315  */
03316 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
03317 {
03318    struct ast_context *c;
03319 
03320    if (ast_lock_contexts()) {
03321       errno = EBUSY;
03322       return -1;
03323    }
03324 
03325    c = ast_walk_contexts(NULL);
03326    while (c) {
03327       if (!strcmp(ast_get_context_name(c), context)) {
03328          int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
03329          ast_unlock_contexts();
03330          return ret;
03331       }
03332       c = ast_walk_contexts(c);
03333    }
03334 
03335    ast_unlock_contexts();
03336    errno = ENOENT;
03337    return -1;
03338 }
03339 
03340 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
03341 {
03342    struct ast_ignorepat *ip, *ipl = NULL;
03343 
03344    if (ast_mutex_lock(&con->lock)) {
03345       errno = EBUSY;
03346       return -1;
03347    }
03348 
03349    ip = con->ignorepats;
03350    while (ip) {
03351       if (!strcmp(ip->pattern, ignorepat) &&
03352          (registrar == ip->registrar || !registrar)) {
03353          if (ipl) {
03354             ipl->next = ip->next;
03355             free(ip);
03356          } else {
03357             con->ignorepats = ip->next;
03358             free(ip);
03359          }
03360          ast_mutex_unlock(&con->lock);
03361          return 0;
03362       }
03363       ipl = ip; ip = ip->next;
03364    }
03365 
03366    ast_mutex_unlock(&con->lock);
03367    errno = EINVAL;
03368    return -1;
03369 }
03370 
03371 /*
03372  * EBUSY - can't lock
03373  * ENOENT - there is no existence of context
03374  */
03375 int ast_context_add_ignorepat(char *con, char *value, char *registrar)
03376 {
03377    struct ast_context *c;
03378 
03379    if (ast_lock_contexts()) {
03380       errno = EBUSY;
03381       return -1;
03382    }
03383 
03384    c = ast_walk_contexts(NULL);
03385    while (c) {
03386       if (!strcmp(ast_get_context_name(c), con)) {
03387          int ret = ast_context_add_ignorepat2(c, value, registrar);
03388          ast_unlock_contexts();
03389          return ret;
03390       } 
03391       c = ast_walk_contexts(c);
03392    }
03393 
03394    ast_unlock_contexts();
03395    errno = ENOENT;
03396    return -1;
03397 }
03398 
03399 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
03400 {
03401    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
03402    ignorepat = malloc(sizeof(struct ast_ignorepat));
03403    if (!ignorepat) {
03404       ast_log(LOG_ERROR, "Out of memory\n");
03405       errno = ENOMEM;
03406       return -1;
03407    }
03408    memset(ignorepat, 0, sizeof(struct ast_ignorepat));
03409    strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
03410    ignorepat->next = NULL;
03411    ignorepat->registrar = registrar;
03412    ast_mutex_lock(&con->lock);
03413    ignorepatc = con->ignorepats;
03414    while(ignorepatc) {
03415       ignorepatl = ignorepatc;
03416       if (!strcasecmp(ignorepatc->pattern, value)) {
03417          /* Already there */
03418          ast_mutex_unlock(&con->lock);
03419          errno = EEXIST;
03420          return -1;
03421       }
03422       ignorepatc = ignorepatc->next;
03423    }
03424    if (ignorepatl) 
03425       ignorepatl->next = ignorepat;
03426    else
03427       con->ignorepats = ignorepat;
03428    ast_mutex_unlock(&con->lock);
03429    return 0;
03430    
03431 }
03432 
03433 int ast_ignore_pattern(char *context, char *pattern)
03434 {
03435    struct ast_context *con;
03436    struct ast_ignorepat *pat;
03437    con = ast_context_find(context);
03438    if (con) {
03439       pat = con->ignorepats;
03440       while (pat) {
03441          if (ast_extension_match(pat->pattern, pattern))
03442             return 1;
03443          pat = pat->next;
03444       }
03445    } 
03446    return 0;
03447 }
03448 
03449 /*
03450  * EBUSY   - can't lock
03451  * ENOENT  - no existence of context
03452  *
03453  */
03454 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
03455    char *application, void *data, void (*datad)(void *), char *registrar)
03456 {
03457    struct ast_context *c;
03458 
03459    if (ast_lock_contexts()) {
03460       errno = EBUSY;
03461       return -1;
03462    }
03463 
03464    c = ast_walk_contexts(NULL);
03465    while (c) {
03466       if (!strcmp(context, ast_get_context_name(c))) {
03467          int ret = ast_add_extension2(c, replace, extension, priority, callerid,
03468             application, data, datad, registrar);
03469          ast_unlock_contexts();
03470          return ret;
03471       }
03472       c = ast_walk_contexts(c);
03473    }
03474 
03475    ast_unlock_contexts();
03476    errno = ENOENT;
03477    return -1;
03478 }
03479 
03480 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority, int needlock)
03481 {
03482    int res = 0;
03483    if (needlock)
03484       ast_mutex_lock(&chan->lock);
03485    if (chan->pbx) {
03486       /* This channel is currently in the PBX */
03487       if (context && strlen(context))
03488          strncpy(chan->context, context, sizeof(chan->context) - 1);
03489       if (exten && strlen(exten))
03490          strncpy(chan->exten, exten, sizeof(chan->context) - 1);
03491       if (priority)
03492          chan->priority = priority - 1;
03493       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
03494       if (needlock)
03495          ast_mutex_unlock(&chan->lock);
03496    } else {
03497       /* In order to do it when the channel doesn't really exist within
03498          the PBX, we have to make a new channel, masquerade, and start the PBX
03499          at the new location */
03500       struct ast_channel *tmpchan;
03501       struct ast_frame *f;
03502       tmpchan = ast_channel_alloc(0);
03503       if (tmpchan) {
03504          snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
03505          ast_setstate(tmpchan, chan->_state);
03506          /* Make formats okay */
03507          tmpchan->readformat = chan->readformat;
03508          tmpchan->writeformat = chan->writeformat;
03509          /* Setup proper location */
03510          if (context && strlen(context))
03511             strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
03512          else
03513             strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
03514          if (exten && strlen(exten))
03515             strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
03516          else
03517             strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
03518          if (priority)
03519             tmpchan->priority = priority;
03520          else
03521             tmpchan->priority = chan->priority;
03522          if (needlock)
03523             ast_mutex_unlock(&chan->lock);
03524          
03525          /* Masquerade into temp channel */
03526          ast_channel_masquerade(tmpchan, chan);
03527          
03528          /* Make the masquerade happen by reading a frame from the tmp channel */
03529          f = ast_read(tmpchan);
03530          if (f)
03531             ast_frfree(f);
03532          /* Start the PBX going on our stolen channel */
03533          if (ast_pbx_start(tmpchan)) {
03534             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
03535             ast_hangup(tmpchan);
03536             res = -1;
03537          }
03538       } else {
03539          res = -1;
03540          if (needlock)
03541             ast_mutex_unlock(&chan->lock);
03542       }
03543    }
03544    return res;
03545 }
03546 
03547 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
03548 {
03549    struct ast_channel *chan;
03550    chan = ast_channel_walk(NULL);
03551    while(chan) {
03552       if (!strcasecmp(channame, chan->name))
03553          break;
03554       chan = ast_channel_walk(chan);
03555    }
03556    if (chan)
03557       return ast_async_goto(chan, context, exten, priority, 1);
03558    return -1;
03559 }
03560 
03561 static void ext_strncpy(char *dst, char *src, int len)
03562 {
03563    int count=0;
03564    while(*src && (count < len - 1)) {
03565       switch(*src) {
03566       case ' ':
03567 //otherwise exten => [a-b],1,... doesn't work
03568 //    case '-':
03569          /* Ignore */
03570          break;
03571       default:
03572          *dst = *src;
03573          dst++;
03574       }
03575       src++;
03576       count++;
03577    }
03578    *dst = '\0';
03579 }
03580 
03581 /*
03582  * EBUSY - can't lock
03583  * EEXIST - extension with the same priority exist and no replace is set
03584  *
03585  */
03586 int ast_add_extension2(struct ast_context *con,
03587                  int replace, char *extension, int priority, char *callerid,
03588                  char *application, void *data, void (*datad)(void *),
03589                  char *registrar)
03590 {
03591 
03592 #define LOG do {  if (option_debug) {\
03593       if (tmp->matchcid) { \
03594          ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
03595       } else { \
03596          ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
03597       } \
03598    } else if (option_verbose > 2) { \
03599       if (tmp->matchcid) { \
03600          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
03601       } else {  \
03602          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
03603       } \
03604    } } while(0)
03605 
03606    /*
03607     * This is a fairly complex routine.  Different extensions are kept
03608     * in order by the extension number.  Then, extensions of different
03609     * priorities (same extension) are kept in a list, according to the
03610     * peer pointer.
03611     */
03612    struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
03613    int res;
03614    /* Be optimistic:  Build the extension structure first */
03615    tmp = malloc(sizeof(struct ast_exten));
03616    if (tmp) {
03617       memset(tmp, 0, sizeof(struct ast_exten));
03618       ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
03619       tmp->priority = priority;
03620       if (callerid) {
03621          ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
03622          tmp->matchcid = 1;
03623       } else {
03624          strcpy(tmp->cidmatch, "");
03625          tmp->matchcid = 0;
03626       }
03627       strncpy(tmp->app, application, sizeof(tmp->app)-1);
03628       tmp->parent = con;
03629       tmp->data = data;
03630       tmp->datad = datad;
03631       tmp->registrar = registrar;
03632       tmp->peer = NULL;
03633       tmp->next =  NULL;
03634    } else {
03635       ast_log(LOG_ERROR, "Out of memory\n");
03636       errno = ENOMEM;
03637       return -1;
03638    }
03639    if (ast_mutex_lock(&con->lock)) {
03640       free(tmp);
03641       /* And properly destroy the data */
03642       datad(data);
03643       ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
03644       errno = EBUSY;
03645       return -1;
03646    }
03647    e = con->root;
03648    while(e) {
03649       res= strcasecmp(e->exten, extension);
03650       if (!res) {
03651          if (!e->matchcid && !tmp->matchcid)
03652             res = 0;
03653          else if (tmp->matchcid && !e->matchcid)
03654             res = 1;
03655          else if (e->matchcid && !tmp->matchcid)
03656             res = -1;
03657          else
03658             res = strcasecmp(e->cidmatch, tmp->cidmatch);
03659       }
03660       if (res == 0) {
03661          /* We have an exact match, now we find where we are
03662             and be sure there's no duplicates */
03663          while(e) {
03664             if (e->priority == tmp->priority) {
03665                /* Can't have something exactly the same.  Is this a
03666                   replacement?  If so, replace, otherwise, bonk. */
03667                if (replace) {
03668                   if (ep) {
03669                      /* We're in the peer list, insert ourselves */
03670                      ep->peer = tmp;
03671                      tmp->peer = e->peer;
03672                   } else if (el) {
03673                      /* We're the first extension. Take over e's functions */
03674                      el->next = tmp;
03675                      tmp->next = e->next;
03676                      tmp->peer = e->peer;
03677                   } else {
03678                      /* We're the very first extension.  */
03679                      con->root = tmp;
03680                      tmp->next = e->next;
03681                      tmp->peer = e->peer;
03682                   }
03683                   if (tmp->priority == PRIORITY_HINT)
03684                       ast_change_hint(e,tmp);
03685                   /* Destroy the old one */
03686                   e->datad(e->data);
03687                   free(e);
03688                   ast_mutex_unlock(&con->lock);
03689                   if (tmp->priority == PRIORITY_HINT)
03690                       ast_change_hint(e, tmp);
03691                   /* And immediately return success. */
03692                   LOG;
03693                   return 0;
03694                } else {
03695                   ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
03696                   tmp->datad(tmp->data);
03697                   free(tmp);
03698                   ast_mutex_unlock(&con->lock);
03699                   errno = EEXIST;
03700                   return -1;
03701                }
03702             } else if (e->priority > tmp->priority) {
03703                /* Slip ourselves in just before e */
03704                if (ep) {
03705                   /* Easy enough, we're just in the peer list */
03706                   ep->peer = tmp;
03707                   tmp->peer = e;
03708                } else if (el) {
03709                   /* We're the first extension in this peer list */
03710                   el->next = tmp;
03711                   tmp->next = e->next;
03712                   e->next = NULL;
03713                   tmp->peer = e;
03714                } else {
03715                   /* We're the very first extension altogether */
03716                   tmp->next = con->root;
03717                   /* Con->root must always exist or we couldn't get here */
03718                   tmp->peer = con->root->peer;
03719                   con->root = tmp;
03720                }
03721                ast_mutex_unlock(&con->lock);
03722                /* And immediately return success. */
03723                if (tmp->priority == PRIORITY_HINT)
03724                    ast_add_hint(tmp);
03725                
03726                LOG;
03727                return 0;
03728             }
03729             ep = e;
03730             e = e->peer;
03731          }
03732          /* If we make it here, then it's time for us to go at the very end.
03733             ep *must* be defined or we couldn't have gotten here. */
03734          ep->peer = tmp;
03735          ast_mutex_unlock(&con->lock);
03736          if (tmp->priority == PRIORITY_HINT)
03737              ast_add_hint(tmp);
03738          
03739          /* And immediately return success. */
03740          LOG;
03741          return 0;
03742             
03743       } else if (res > 0) {
03744          /* Insert ourselves just before 'e'.  We're the first extension of
03745             this kind */
03746          tmp->next = e;
03747          if (el) {
03748             /* We're in the list somewhere */
03749             el->next = tmp;
03750          } else {
03751             /* We're at the top of the list */
03752             con->root = tmp;
03753          }
03754          ast_mutex_unlock(&con->lock);
03755          if (tmp->priority == PRIORITY_HINT)
03756              ast_add_hint(tmp);
03757 
03758          /* And immediately return success. */
03759          LOG;
03760          return 0;
03761       }        
03762          
03763       el = e;
03764       e = e->next;
03765    }
03766    /* If we fall all the way through to here, then we need to be on the end. */
03767    if (el)
03768       el->next = tmp;
03769    else
03770       con->root = tmp;
03771    ast_mutex_unlock(&con->lock);
03772    if (tmp->priority == PRIORITY_HINT)
03773        ast_add_hint(tmp);
03774    LOG;
03775    return 0;   
03776 }
03777 
03778 struct async_stat {
03779    pthread_t p;
03780    struct ast_channel *chan;
03781    char context[AST_MAX_EXTENSION];
03782    char exten[AST_MAX_EXTENSION];
03783    int priority;
03784    int timeout;
03785    char app[AST_MAX_EXTENSION];
03786    char appdata[1024];
03787 };
03788 
03789 static void *async_wait(void *data) 
03790 {
03791    struct async_stat *as = data;
03792    struct ast_channel *chan = as->chan;
03793    int timeout = as->timeout;
03794    int res;
03795    struct ast_frame *f;
03796    struct ast_app *app;
03797    
03798    while(timeout && (chan->_state != AST_STATE_UP)) {
03799       res = ast_waitfor(chan, timeout);
03800       if (res < 1) 
03801          break;
03802       if (timeout > -1)
03803          timeout = res;
03804       f = ast_read(chan);
03805       if (!f)
03806          break;
03807       if (f->frametype == AST_FRAME_CONTROL) {
03808          if ((f->subclass == AST_CONTROL_BUSY)  ||
03809             (f->subclass == AST_CONTROL_CONGESTION) )
03810                break;
03811       }
03812       ast_frfree(f);
03813    }
03814    if (chan->_state == AST_STATE_UP) {
03815       if (strlen(as->app)) {
03816          app = pbx_findapp(as->app);
03817          if (app) {
03818             if (option_verbose > 2)
03819                ast_verbose(VERBOSE_PREFIX_3 "Lauching %s(%s) on %s\n", as->app, as->appdata, chan->name);
03820             pbx_exec(chan, app, as->appdata, 1);
03821          } else
03822             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
03823       } else {
03824          if (strlen(as->context))
03825             strncpy(chan->context, as->context, sizeof(chan->context) - 1);
03826          if (strlen(as->exten))
03827             strncpy(chan->exten, as->exten, sizeof(chan->exten) - 1);
03828          if (as->priority > 0)
03829             chan->priority = as->priority;
03830          /* Run the PBX */
03831          if (ast_pbx_run(chan)) {
03832             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
03833          } else {
03834             /* PBX will have taken care of this */
03835             chan = NULL;
03836          }
03837       }
03838          
03839    }
03840    free(as);
03841    if (chan)
03842       ast_hangup(chan);
03843    return NULL;
03844 }
03845 
03846 int ast_pbx_outgoing_exten(char *type, int format, void *data, int timeout, char *context, char *exten, int priority, int *reason, int sync, char *callerid, char *variable, char *account)
03847 {
03848    struct ast_channel *chan;
03849    struct async_stat *as;
03850    int res = -1;
03851    char *var, *tmp;
03852    struct outgoing_helper oh;
03853    pthread_attr_t attr;
03854       
03855    if (sync) {
03856       LOAD_OH(oh);
03857       chan = __ast_request_and_dial(type, format, data, timeout, reason, callerid, &oh);
03858       if (chan) {
03859          pbx_builtin_setaccount(chan, account);
03860          if (chan->_state == AST_STATE_UP) {
03861                res = 0;
03862             if (option_verbose > 3)
03863                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
03864 
03865             if (sync > 1) {
03866                if (ast_pbx_run(chan)) {
03867                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
03868                   ast_hangup(chan);
03869                   res = -1;
03870                }
03871             } else {
03872                if (ast_pbx_start(chan)) {
03873                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
03874                   ast_hangup(chan);
03875                   res = -1;
03876                } 
03877             }
03878          } else {
03879             if (option_verbose > 3)
03880                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
03881             ast_hangup(chan);
03882          }
03883       } else {
03884          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
03885          /* check if "failed" exists */
03886          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
03887             chan = ast_channel_alloc(0);
03888             if (chan) {
03889                strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1);
03890                if (context && strlen(context))
03891                   strncpy(chan->context, context, sizeof(chan->context) - 1);
03892                strncpy(chan->exten, "failed", sizeof(chan->exten) - 1);
03893                chan->priority = 1;
03894                if (variable) {
03895                   tmp = ast_strdupa(variable);
03896                   for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) {
03897                      pbx_builtin_setvar( chan, var );
03898                   }
03899                }
03900                ast_pbx_run(chan);   
03901             } else
03902                ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
03903          }
03904       }
03905    } else {
03906       as = malloc(sizeof(struct async_stat));
03907       if (!as)
03908          return -1;
03909       memset(as, 0, sizeof(struct async_stat));
03910       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
03911       if (!chan) {
03912          free(as);
03913          return -1;
03914       }
03915       pbx_builtin_setaccount(chan, account);
03916       as->chan = chan;
03917       strncpy(as->context, context, sizeof(as->context) - 1);
03918       strncpy(as->exten,  exten, sizeof(as->exten) - 1);
03919       as->priority = priority;
03920       as->timeout = timeout;
03921       pthread_attr_init(&attr);
03922       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03923       if (pthread_create(&as->p, &attr, async_wait, as)) {
03924          ast_log(LOG_WARNING, "Failed to start async wait\n");
03925          free(as);
03926          ast_hangup(chan);
03927          return -1;
03928       }
03929       res = 0;
03930    }
03931    return res;
03932 }
03933 
03934 struct app_tmp {
03935    char app[256];
03936    char data[256];
03937    struct ast_channel *chan;
03938    pthread_t t;
03939 };
03940 
03941 static void *ast_pbx_run_app(void *data)
03942 {
03943    struct app_tmp *tmp = data;
03944    struct ast_app *app;
03945    app = pbx_findapp(tmp->app);
03946    if (app) {
03947       if (option_verbose > 3)
03948          ast_verbose(VERBOSE_PREFIX_4 "Lauching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
03949       pbx_exec(tmp->chan, app, tmp->data, 1);
03950    } else
03951       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
03952    ast_hangup(tmp->chan);
03953    free(tmp);
03954    return NULL;
03955 }
03956 
03957 int ast_pbx_outgoing_app(char *type, int format, void *data, int timeout, char *app, char *appdata, int *reason, int sync, char *callerid, char *variable, char *account)
03958 {
03959    struct ast_channel *chan;
03960    struct async_stat *as;
03961    struct app_tmp *tmp;
03962    char *var, *vartmp;
03963    int res = -1;
03964    pthread_attr_t attr;
03965    
03966    if (!app || !strlen(app))
03967       return -1;
03968    if (sync) {
03969       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
03970       if (chan) {
03971          pbx_builtin_setaccount(chan, account);
03972          if (variable) {
03973             vartmp = ast_strdupa(variable);
03974             for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) {
03975                pbx_builtin_setvar( chan, var );
03976             }
03977          }
03978          if (chan->_state == AST_STATE_UP) {
03979             res = 0;
03980             if (option_verbose > 3)
03981                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
03982             tmp = malloc(sizeof(struct app_tmp));
03983             if (tmp) {
03984                memset(tmp, 0, sizeof(struct app_tmp));
03985                strncpy(tmp->app, app, sizeof(tmp->app) - 1);
03986                strncpy(tmp->data, appdata, sizeof(tmp->data) - 1);
03987                tmp->chan = chan;
03988                if (sync > 1) {
03989                   ast_pbx_run_app(tmp);
03990                } else {
03991                   pthread_attr_init(&attr);
03992                   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
03993                   if (pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
03994                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
03995                      free(tmp);
03996                      ast_hangup(chan);
03997                      res = -1;
03998                   }
03999                }
04000             } else {
04001                ast_log(LOG_ERROR, "Out of memory :(\n");
04002                res = -1;
04003             }
04004          } else {
04005             if (option_verbose > 3)
04006                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
04007             ast_hangup(chan);
04008          }
04009       }
04010    } else {
04011       as = malloc(sizeof(struct async_stat));
04012       if (!as)
04013          return -1;
04014       memset(as, 0, sizeof(struct async_stat));
04015       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
04016       if (!chan) {
04017          free(as);
04018          return -1;
04019       }
04020       pbx_builtin_setaccount(chan, account);
04021       as->chan = chan;
04022       strncpy(as->app, app, sizeof(as->app) - 1);
04023       if (appdata)
04024          strncpy(as->appdata,  appdata, sizeof(as->appdata) - 1);
04025       as->timeout = timeout;
04026       if (pthread_create(&as->p, NULL, async_wait, as)) {
04027          ast_log(LOG_WARNING, "Failed to start async wait\n");
04028          free(as);
04029          ast_hangup(chan);
04030          return -1;
04031       }
04032       res = 0;
04033    }
04034    return res;
04035 }
04036 
04037 static void destroy_exten(struct ast_exten *e)
04038 {
04039    if (e->priority == PRIORITY_HINT)
04040       ast_remove_hint(e);
04041 
04042    if (e->datad)
04043       e->datad(e->data);
04044    free(e);
04045 }
04046 
04047 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock)
04048 {
04049    struct ast_context *tmp, *tmpl=NULL;
04050    struct ast_include *tmpi, *tmpil= NULL;
04051    struct ast_sw *sw, *swl= NULL;
04052    struct ast_exten *e, *el, *en;
04053    if (lock)
04054       ast_mutex_lock(&conlock);
04055    tmp = contexts;
04056    while(tmp) {
04057       if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
04058           (!registrar || !strcasecmp(registrar, tmp->registrar))) {
04059          /* Okay, let's lock the structure to be sure nobody else
04060             is searching through it. */
04061          if (ast_mutex_lock(&tmp->lock)) {
04062             ast_log(LOG_WARNING, "Unable to lock context lock\n");
04063             return;
04064          }
04065          if (tmpl)
04066             tmpl->next = tmp->next;
04067          else
04068             contexts = tmp->next;
04069          /* Okay, now we're safe to let it go -- in a sense, we were
04070             ready to let it go as soon as we locked it. */
04071          ast_mutex_unlock(&tmp->lock);
04072          for (tmpi = tmp->includes; tmpi; ) {
04073             /* Free includes */
04074             tmpil = tmpi;
04075             tmpi = tmpi->next;
04076             free(tmpil);
04077             tmpil = tmpi;
04078          }
04079          for (sw = tmp->alts; sw; ) {
04080             swl = sw;
04081             sw = sw->next;
04082             free(swl);
04083             swl = sw;
04084          }
04085          for (e = tmp->root; e;) {
04086             for (en = e->peer; en;) {
04087                el = en;
04088                en = en->peer;
04089                destroy_exten(el);
04090             }
04091             el = e;
04092             e = e->next;
04093             destroy_exten(el);
04094          }
04095          free(tmp);
04096          if (!con) {
04097             /* Might need to get another one -- restart */
04098             tmp = contexts;
04099             tmpl = NULL;
04100             tmpil = NULL;
04101             continue;
04102          }
04103          if (lock)
04104             ast_mutex_unlock(&conlock);
04105          return;
04106       }
04107       tmpl = tmp;
04108       tmp = tmp->next;
04109    }
04110    if (lock)
04111       ast_mutex_unlock(&conlock);
04112 }
04113 
04114 void ast_context_destroy(struct ast_context *con, char *registrar)
04115 {
04116    __ast_context_destroy(con,registrar,1);
04117 }
04118 
04119 static void wait_for_hangup(struct ast_channel *chan)
04120 {
04121    int res;
04122    struct ast_frame *f;
04123    do {
04124       res = ast_waitfor(chan, -1);
04125       if (res < 0)
04126          return;
04127       f = ast_read(chan);
04128       if (f)
04129          ast_frfree(f);
04130    } while(f);
04131 }
04132 
04133 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
04134 {
04135    ast_indicate(chan, AST_CONTROL_RINGING);
04136    return 0;
04137 }
04138 
04139 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
04140 {
04141    ast_indicate(chan, AST_CONTROL_BUSY);     
04142    wait_for_hangup(chan);
04143    return -1;
04144 }
04145 
04146 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
04147 {
04148    ast_indicate(chan, AST_CONTROL_CONGESTION);
04149    wait_for_hangup(chan);
04150    return -1;
04151 }
04152 
04153 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
04154 {
04155    return ast_answer(chan);
04156 }
04157 
04158 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
04159 {
04160    /* Copy the language as specified */
04161    strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
04162    return 0;
04163 }
04164 
04165 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
04166 {
04167    /* Reset the CDR as specified */
04168    if (data)
04169       ast_cdr_reset(chan->cdr, strchr((char *)data, 'w') ? 1 : 0);
04170    else
04171       ast_cdr_reset(chan->cdr, 0);
04172    return 0;
04173 }
04174 
04175 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
04176 {
04177    /* Copy the language as specified */
04178    if (data)
04179       ast_cdr_setaccount(chan, (char *)data);
04180    else
04181       ast_cdr_setaccount(chan, "");
04182    return 0;
04183 }
04184 
04185 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
04186 {
04187    /* Just return non-zero and it will hang up */
04188    return -1;
04189 }
04190 
04191 static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
04192 {
04193    char newexten[AST_MAX_EXTENSION] = "";
04194    if (!data || !atoi(data)) {
04195       ast_log(LOG_DEBUG, "Ignoring, since number of digits to strip is 0\n");
04196       return 0;
04197    }
04198    if (strlen(chan->exten) > atoi(data)) {
04199       strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1);
04200    }
04201    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04202    return 0;
04203 }
04204 
04205 static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
04206 {
04207    char newexten[AST_MAX_EXTENSION] = "";
04208    if (!data || !strlen(data)) {
04209       ast_log(LOG_DEBUG, "Ignoring, since there is no prefix to add\n");
04210       return 0;
04211    }
04212    snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
04213    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04214    if (option_verbose > 2)
04215       ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
04216    return 0;
04217 }
04218 
04219 static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
04220 {
04221    char newexten[AST_MAX_EXTENSION] = "";
04222    if (!data || !strlen(data)) {
04223       ast_log(LOG_DEBUG, "Ignoring, since there is no suffix to add\n");
04224       return 0;
04225    }
04226    snprintf(newexten, sizeof(newexten), "%s%s", chan->exten, (char *)data);
04227    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04228    if (option_verbose > 2)
04229       ast_verbose(VERBOSE_PREFIX_3 "Appended suffix, new extension is %s\n", chan->exten);
04230    return 0;
04231 }
04232 
04233 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
04234 {
04235    int res=0;
04236    char *s, *ts;
04237    struct ast_include include;
04238 
04239    if (!data) {
04240       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
04241       return -1;
04242    }
04243 
04244    s = strdup((char *) data);
04245    ts = s;
04246 
04247    /* Separate the Goto path */
04248    strsep(&ts,"?");
04249 
04250    // [PHM 07/01/03]
04251    // struct ast_include include contained garbage here, fixed by zeroing it on get_timerange
04252    build_timing(&include, s);
04253    if (include_valid(&include))
04254       res = pbx_builtin_goto(chan, (void *)ts);
04255    free(s);
04256    return res;
04257 }
04258 
04259 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
04260 {
04261    int ms;
04262    /* Wait for "n" seconds */
04263    if (data && atoi((char *)data)) {
04264       ms = atoi((char *)data) * 1000;
04265       return ast_safe_sleep(chan, ms);
04266    }
04267    return 0;
04268 }
04269 
04270 static int pbx_builtin_background(struct ast_channel *chan, void *data)
04271 {
04272    int res;
04273    /* Answer if need be */
04274    if (chan->_state != AST_STATE_UP)
04275       if (ast_answer(chan))
04276          return -1;
04277    /* Stop anything playing */
04278    ast_stopstream(chan);
04279    /* Stream a file */
04280    res = ast_streamfile(chan, (char *)data, chan->language);
04281    if (!res) {
04282       res = ast_waitstream(chan, AST_DIGIT_ANY);
04283       ast_stopstream(chan);
04284    }
04285    return res;
04286 }
04287 
04288 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
04289 {
04290    int x = atoi((char *) data);
04291    /* Set the timeout for how long to wait between digits */
04292    ast_channel_setwhentohangup(chan,x);
04293    if (option_verbose > 2)
04294       ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
04295    return 0;
04296 }
04297 
04298 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
04299 {
04300    /* Set the timeout for how long to wait between digits */
04301    chan->pbx->rtimeout = atoi((char *)data);
04302    if (option_verbose > 2)
04303       ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
04304    return 0;
04305 }
04306 
04307 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
04308 {
04309    /* Set the timeout for how long to wait between digits */
04310    chan->pbx->dtimeout = atoi((char *)data);
04311    if (option_verbose > 2)
04312       ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
04313    return 0;
04314 }
04315 
04316 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
04317 {
04318    char *s;
04319    char *exten, *pri, *context;
04320    char *stringp=NULL;
04321    if (!data || !strlen(data)) {
04322       ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
04323       return -1;
04324    }
04325    s = strdup((void *) data);
04326    stringp=s;
04327    context = strsep(&stringp, "|");
04328    exten = strsep(&stringp, "|");
04329    if (!exten) {
04330       /* Only a priority in this one */
04331       pri = context;
04332       exten = NULL;
04333       context = NULL;
04334    } else {
04335       pri = strsep(&stringp, "|");
04336       if (!pri) {
04337          /* Only an extension and priority in this one */
04338          pri = exten;
04339          exten = context;
04340          context = NULL;
04341       }
04342    }
04343    if (atoi(pri) < 0) {
04344       ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
04345       free(s);
04346       return -1;
04347    }
04348    /* At this point we have a priority and maybe an extension and a context */
04349    chan->priority = atoi(pri) - 1;
04350    if (exten && strcasecmp(exten, "BYEXTENSION"))
04351       strncpy(chan->exten, exten, sizeof(chan->exten)-1);
04352    if (context)
04353       strncpy(chan->context, context, sizeof(chan->context)-1);
04354    if (option_verbose > 2)
04355       ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
04356    ast_cdr_update(chan);
04357    return 0;
04358 }
04359 
04360 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name) {
04361    struct ast_var_t *variables;
04362    struct varshead *headp;
04363 
04364     if (chan)
04365         headp=&chan->varshead;
04366    else
04367       headp=&globals;
04368 
04369    if (name) {
04370       AST_LIST_TRAVERSE(headp,variables,entries) {
04371          if (!strcmp(name, ast_var_name(variables)))
04372             return ast_var_value(variables);
04373       }
04374       if (headp != &globals) {
04375          /* Check global variables if we haven't already */
04376          headp = &globals;
04377          AST_LIST_TRAVERSE(headp,variables,entries) {
04378             if (!strcmp(name, ast_var_name(variables)))
04379                return ast_var_value(variables);
04380          }
04381       }
04382    }
04383    return NULL;
04384 }
04385 
04386 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value) {
04387    struct ast_var_t *newvariable;
04388         struct varshead *headp;
04389     if (chan)
04390         headp=&chan->varshead;
04391    else
04392       headp=&globals;
04393                 
04394    AST_LIST_TRAVERSE (headp,newvariable,entries) {
04395       if (strcasecmp(ast_var_name(newvariable),name)==0) {
04396          /* there is already such a variable, delete it */
04397          AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries);
04398          ast_var_delete(newvariable);
04399          break;
04400       }
04401    } 
04402    
04403    if (value) {
04404       if ((option_verbose > 1) && (headp == &globals))
04405          ast_verbose(VERBOSE_PREFIX_3 "Setting global variable '%s' to '%s'\n",name, value);
04406       newvariable=ast_var_assign(name,value);   
04407       AST_LIST_INSERT_HEAD(headp,newvariable,entries);
04408    }
04409 }
04410 
04411 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
04412 {
04413    char *name;
04414    char *value;
04415    char *stringp=NULL;
04416                 
04417    if (!data || !strlen(data)) {
04418       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04419       return 0;
04420    }
04421    
04422    stringp=data;
04423    name=strsep(&stringp,"=");
04424    value=strsep(&stringp,"\0"); 
04425    
04426    pbx_builtin_setvar_helper(chan,name,value);
04427          
04428         return(0);
04429 }
04430 
04431 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
04432 {
04433    char *name;
04434    char *value;
04435    char *stringp=NULL;
04436                 
04437    if (!data || !strlen(data)) {
04438       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04439       return 0;
04440    }
04441    
04442    stringp=data;
04443    name=strsep(&stringp,"=");
04444    value=strsep(&stringp,"\0"); 
04445    
04446    pbx_builtin_setvar_helper(NULL,name,value);
04447          
04448         return(0);
04449 }
04450 
04451 
04452 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
04453 {
04454    return 0;
04455 }
04456 
04457 
04458 void pbx_builtin_clear_globals(void)
04459 {
04460    struct ast_var_t *vardata;
04461    while (!AST_LIST_EMPTY(&globals)) {
04462       vardata = AST_LIST_FIRST(&globals);
04463       AST_LIST_REMOVE_HEAD(&globals, entries);
04464       ast_var_delete(vardata);
04465    }
04466 }
04467 
04468 static int pbx_checkcondition(char *condition) {
04469    char *s;
04470    int ret;
04471    
04472    s=strdup(condition);
04473    
04474    ret=1;
04475    
04476    if ((strcasecmp(s,"0")) || (strlen(s)==0)) {
04477       ret=0;
04478    }
04479    
04480    free(s);
04481    return(ret);
04482 }
04483 
04484 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
04485 {
04486    char *condition,*branch1,*branch2,*branch;
04487    char *s;
04488    int rc;
04489    char *stringp=NULL;
04490 
04491    if (!data || !strlen(data)) {
04492       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
04493       return 0;
04494    }
04495    
04496    s=strdup(data);
04497    stringp=s;
04498    condition=strsep(&stringp,"?");
04499    branch1=strsep(&stringp,":");
04500    branch2=strsep(&stringp,"");
04501    
04502    if (pbx_checkcondition(condition)) {
04503       branch=branch2;
04504    } else {
04505       branch=branch1;
04506    }
04507    
04508    if ((branch==NULL) || (strlen(branch)==0)) {
04509       ast_log(LOG_NOTICE, "Not taking any branch\n");
04510       return(0);
04511    }
04512    
04513    rc=pbx_builtin_goto(chan,branch);
04514    free(s);
04515    return(rc);
04516 }           
04517 
04518 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
04519 {
04520    int res = 0;
04521    if (data && atoi((char *)data) )
04522       res = ast_say_number(chan, atoi((char *)data), "", chan->language);
04523    return res;
04524 }
04525 
04526 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
04527 {
04528    int res = 0;
04529    if (data)
04530       res = ast_say_digit_str(chan, (char *)data, "", chan->language);
04531    return res;
04532 }
04533    
04534 int load_pbx(void)
04535 {
04536    int x;
04537    /* Initialize the PBX */
04538    if (option_verbose) {
04539       ast_verbose( "Asterisk PBX Core Initializing\n");
04540       ast_verbose( "Registering builtin applications:\n");
04541    }
04542    ast_cli_register(&show_applications_cli);
04543    ast_cli_register(&show_application_cli);
04544    ast_cli_register(&show_dialplan_cli);
04545    ast_cli_register(&show_switches_cli);
04546    for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
04547       if (option_verbose)
04548          ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
04549       if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
04550          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
04551          return -1;
04552       }
04553    }
04554    return 0;
04555 }
04556 
04557 /*
04558  * Lock context list functions ...
04559  */
04560 int ast_lock_contexts()
04561 {
04562    return ast_mutex_lock(&conlock);
04563 }
04564 
04565 int ast_unlock_contexts()
04566 {
04567    return ast_mutex_unlock(&conlock);
04568 }
04569 
04570 /*
04571  * Lock context ...
04572  */
04573 int ast_lock_context(struct ast_context *con)
04574 {
04575    return ast_mutex_lock(&con->lock);
04576 }
04577 
04578 int ast_unlock_context(struct ast_context *con)
04579 {
04580    return ast_mutex_unlock(&con->lock);
04581 }
04582 
04583 /*
04584  * Name functions ...
04585  */
04586 char *ast_get_context_name(struct ast_context *con)
04587 {
04588    return con ? con->name : NULL;
04589 }
04590 
04591 char *ast_get_extension_name(struct ast_exten *exten)
04592 {
04593    return exten ? exten->exten : NULL;
04594 }
04595 
04596 char *ast_get_include_name(struct ast_include *inc)
04597 {
04598    return inc ? inc->name : NULL;
04599 }
04600 
04601 char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
04602 {
04603    return ip ? ip->pattern : NULL;
04604 }
04605 
04606 int ast_get_extension_priority(struct ast_exten *exten)
04607 {
04608    return exten ? exten->priority : -1;
04609 }
04610 
04611 /*
04612  * Registrar info functions ...
04613  */
04614 char *ast_get_context_registrar(struct ast_context *c)
04615 {
04616    return c ? c->registrar : NULL;
04617 }
04618 
04619 char *ast_get_extension_registrar(struct ast_exten *e)
04620 {
04621    return e ? e->registrar : NULL;
04622 }
04623 
04624 char *ast_get_include_registrar(struct ast_include *i)
04625 {
04626    return i ? i->registrar : NULL;
04627 }
04628 
04629 char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
04630 {
04631    return ip ? ip->registrar : NULL;
04632 }
04633 
04634 char *ast_get_extension_app(struct ast_exten *e)
04635 {
04636    return e ? e->app : NULL;
04637 }
04638 
04639 void *ast_get_extension_app_data(struct ast_exten *e)
04640 {
04641    return e ? e->data : NULL;
04642 }
04643 
04644 char *ast_get_switch_name(struct ast_sw *sw)
04645 {
04646    return sw ? sw->name : NULL;
04647 }
04648 
04649 char *ast_get_switch_data(struct ast_sw *sw)
04650 {
04651    return sw ? sw->data : NULL;
04652 }
04653 
04654 char *ast_get_switch_registrar(struct ast_sw *sw)
04655 {
04656    return sw ? sw->registrar : NULL;
04657 }
04658 
04659 /*
04660  * Walking functions ...
04661  */
04662 struct ast_context *ast_walk_contexts(struct ast_context *con)
04663 {
04664    if (!con)
04665       return contexts;
04666    else
04667       return con->next;
04668 }
04669 
04670 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
04671    struct ast_exten *exten)
04672 {
04673    if (!exten)
04674       return con ? con->root : NULL;
04675    else
04676       return exten->next;
04677 }
04678 
04679 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
04680    struct ast_sw *sw)
04681 {
04682    if (!sw)
04683       return con ? con->alts : NULL;
04684    else
04685       return sw->next;
04686 }
04687 
04688 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
04689    struct ast_exten *priority)
04690 {
04691    if (!priority)
04692       return exten;
04693    else
04694       return priority->peer;
04695 }
04696 
04697 struct ast_include *ast_walk_context_includes(struct ast_context *con,
04698    struct ast_include *inc)
04699 {
04700    if (!inc)
04701       return con ? con->includes : NULL;
04702    else
04703       return inc->next;
04704 }
04705 
04706 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
04707    struct ast_ignorepat *ip)
04708 {
04709    if (!ip)
04710       return con ? con->ignorepats : NULL;
04711    else
04712       return ip->next;
04713 }
04714 
04715 int ast_context_verify_includes(struct ast_context *con)
04716 {
04717    struct ast_include *inc;
04718    int res = 0;
04719 
04720    for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
04721       if (!ast_context_find(inc->rname)) {
04722          res = -1;
04723          ast_log(LOG_WARNING, "Context '%s' tries includes non-existant context '%s'\n",
04724                ast_get_context_name(con), inc->rname);
04725       }
04726    return res;
04727 }
04728 

Generated on Fri Feb 27 12:19:43 2004 for Asterisk by doxygen 1.3.5