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_setvar(struct ast_channel *, void *);
00166 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
00167 static int pbx_builtin_noop(struct ast_channel *, void *);
00168 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00169 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00170 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00171 static int pbx_builtin_saydigits(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 "  Setvar(#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 'demo-\n"
00310 "congrats-fr' 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 derprecated 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, "UNIQUEID")) {
00863      snprintf(workspace, workspacelen -1, "%s", c->uniqueid);
00864    } else {
00865       if (c) {
00866          AST_LIST_TRAVERSE(headp,variables,entries) {
00867 #if 0
00868             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
00869 #endif
00870             if (strcasecmp(ast_var_name(variables),var)==0) {
00871                *ret=ast_var_value(variables);
00872                if (*ret) {
00873                   strncpy(workspace, *ret, workspacelen - 1);
00874                   *ret = workspace;
00875                }
00876             }
00877          }
00878       }
00879       if (!(*ret)) {
00880          /* Try globals */
00881          AST_LIST_TRAVERSE(&globals,variables,entries) {
00882 #if 0
00883             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
00884 #endif
00885             if (strcasecmp(ast_var_name(variables),var)==0) {
00886                *ret=ast_var_value(variables);
00887                if (*ret) {
00888                   strncpy(workspace, *ret, workspacelen - 1);
00889                   *ret = workspace;
00890                }
00891             }
00892          }
00893       }
00894       if (!(*ret)) {
00895          int len=strlen(var);
00896          int len_env=strlen("ENV(");
00897          if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
00898             char cp3[80] = "";
00899             strncpy(cp3, var, sizeof(cp3) - 1);
00900             cp3[len-1]='\0';
00901             *ret=getenv(cp3+len_env);
00902             if (*ret) {
00903                strncpy(workspace, *ret, workspacelen - 1);
00904                *ret = workspace;
00905             }
00906          }
00907       }
00908       if (!(*ret) && !strncasecmp(var,"LEN(",4)) {
00909          int len=strlen(var);
00910          int len_len=4;
00911          if (len > (len_len+1) && !strncasecmp(var,"LEN(",len_len) && strchr(var+len_len+2,')')) {
00912             char cp3[80];
00913             strncpy(cp3, var, sizeof(cp3) - 1);
00914             cp3[len-len_len-1]='\0';
00915             sprintf(workspace,"%d",strlen(cp3));
00916             *ret = workspace;
00917          } else ast_log(LOG_NOTICE, "Wrong use of LEN(VARIABLE)\n");
00918       }
00919    }
00920 }
00921 
00922 void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp1,char *cp2,int count)
00923 {
00924    char *cp4;
00925    const char *tmp, *whereweare;
00926    int length;
00927    char workspace[256];
00928    char ltmp[256], var[256];
00929    char *nextvar, *nextexp;
00930    char *vars, *vare;
00931    int pos, brackets, needsub, len;
00932 
00933    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
00934       zero-filled */
00935    whereweare=tmp=cp1;
00936    while(strlen(whereweare) && count) {
00937       /* Assume we're copying the whole remaining string */
00938       pos = strlen(whereweare);
00939 
00940       /* Look for a variable */
00941       nextvar = strstr(whereweare, "${");
00942       
00943       nextexp = strstr(whereweare, "$[");
00944       
00945       if (nextvar && nextexp) {
00946          if (nextvar < nextexp)
00947             nextexp = NULL;
00948          else
00949             nextvar = NULL;
00950       }
00951       
00952       /* If there is one, we only go that far */
00953       if (nextvar)
00954          pos = nextvar - whereweare;
00955       else if (nextexp)
00956          pos = nextexp - whereweare;
00957       
00958       /* Can't copy more than 'count' bytes */
00959       if (pos > count)
00960          pos = count;
00961       
00962       /* Copy that many bytes */
00963       memcpy(cp2, whereweare, pos);
00964       
00965       count -= pos;
00966       cp2 += pos;
00967       whereweare += pos;
00968       
00969       if (nextvar) {
00970          /* We have a variable.  Find the start and end, and determine
00971             if we are going to have to recursively call ourselves on the
00972             contents */
00973          vars = vare = nextvar + 2;
00974          brackets = 1;
00975          needsub = 0;
00976          
00977          /* Find the end of it */
00978          while(brackets && *vare) {
00979             if ((vare[0] == '$') && (vare[1] == '{')) {
00980                needsub++;
00981                brackets++;
00982             } else if (vare[0] == '}') {
00983                brackets--;
00984             } else if ((vare[0] == '$') && (vare[1] == '['))
00985                needsub++;
00986             vare++;
00987          }
00988          if (brackets)
00989             ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
00990          len = vare - vars - 1;
00991          
00992          /* Skip totally over variable name */
00993          whereweare += ( len + 3);
00994          
00995          /* Store variable name (and truncate) */
00996          memset(var, 0, sizeof(var));
00997          strncpy(var, vars, sizeof(var) - 1);
00998          var[len] = '\0';
00999          
01000          /* Substitute if necessary */
01001          if (needsub) {
01002             memset(ltmp, 0, sizeof(ltmp));
01003             pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
01004             vars = ltmp;
01005          } else {
01006             vars = var;
01007          }
01008          
01009          /* Retrieve variable value */
01010          strcpy(workspace, "");
01011          pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
01012          if (cp4) {
01013             length = strlen(cp4);
01014             if (length > count)
01015                length = count;
01016             memcpy(cp2, cp4, length);
01017             count -= length;
01018             cp2 += length;
01019          }
01020          
01021       } else if (nextexp) {
01022          /* We have an expression.  Find the start and end, and determine
01023             if we are going to have to recursively call ourselves on the
01024             contents */
01025          vars = vare = nextexp + 2;
01026          brackets = 1;
01027          needsub = 0;
01028          
01029          /* Find the end of it */
01030          while(brackets && *vare) {
01031             if ((vare[0] == '$') && (vare[1] == '[')) {
01032                needsub++;
01033                brackets++;
01034             } else if (vare[0] == ']') {
01035                brackets--;
01036             } else if ((vare[0] == '$') && (vare[1] == '{'))
01037                needsub++;
01038             vare++;
01039          }
01040          if (brackets)
01041             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
01042          len = vare - vars - 1;
01043          
01044          /* Skip totally over variable name */
01045          whereweare += ( len + 3);
01046          
01047          /* Store variable name (and truncate) */
01048          memset(var, 0, sizeof(var));
01049          strncpy(var, vars, sizeof(var) - 1);
01050          var[len] = '\0';
01051          
01052          /* Substitute if necessary */
01053          if (needsub) {
01054             memset(ltmp, 0, sizeof(ltmp));
01055             pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
01056             vars = ltmp;
01057          } else {
01058             vars = var;
01059          }
01060 
01061          /* Evaluate expression */        
01062          cp4 = ast_expr(vars);
01063          
01064          ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
01065          
01066          if (cp4) {
01067             length = strlen(cp4);
01068             if (length > count)
01069                length = count;
01070             memcpy(cp2, cp4, length);
01071             count -= length;
01072             cp2 += length;
01073             free(cp4);
01074          }
01075          
01076       } else
01077          break;
01078    }
01079 }
01080 
01081 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
01082         
01083    memset(passdata, 0, datalen);
01084       
01085    /* No variables or expressions in e->data, so why scan it? */
01086    if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
01087       strncpy(passdata, e->data, datalen - 1);
01088       passdata[datalen-1] = '\0';
01089       return;
01090    }
01091    
01092    pbx_substitute_variables_helper(c,e->data,passdata, datalen - 1);
01093 }                                                     
01094 
01095 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action) 
01096 {
01097    struct ast_exten *e;
01098    struct ast_app *app;
01099    struct ast_switch *sw;
01100    char *data;
01101    int newstack = 0;
01102    int res;
01103    int status = 0;
01104    char *incstack[AST_PBX_MAX_STACK];
01105    char passdata[256];
01106    int stacklen = 0;
01107    char tmp[80];
01108    char tmp2[80];
01109    char tmp3[256];
01110    if (ast_mutex_lock(&conlock)) {
01111       ast_log(LOG_WARNING, "Unable to obtain lock\n");
01112       if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
01113          return 0;
01114       else
01115          return -1;
01116    }
01117    e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
01118    if (e) {
01119       switch(action) {
01120       case HELPER_CANMATCH:
01121          ast_mutex_unlock(&conlock);
01122          return -1;
01123       case HELPER_EXISTS:
01124          ast_mutex_unlock(&conlock);
01125          return -1;
01126       case HELPER_MATCHMORE:
01127          ast_mutex_unlock(&conlock);
01128          return -1;
01129       case HELPER_SPAWN:
01130          newstack++;
01131          /* Fall through */
01132       case HELPER_EXEC:
01133          app = pbx_findapp(e->app);
01134          ast_mutex_unlock(&conlock);
01135          if (app) {
01136             if (c->context != context)
01137                strncpy(c->context, context, sizeof(c->context-1));
01138             if (c->exten != exten)
01139                strncpy(c->exten, exten, sizeof(c->exten)-1);
01140             c->priority = priority;
01141             pbx_substitute_variables(passdata, sizeof(passdata), c, e);
01142             if (option_debug)
01143                   ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
01144             else if (option_verbose > 2)
01145                   ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
01146                         term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
01147                         term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
01148                         term_color(tmp3, (strlen(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
01149                         (newstack ? "in new stack" : "in same stack"));
01150             res = pbx_exec(c, app, passdata, newstack);
01151             return res;
01152          } else {
01153             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
01154             return -1;
01155          }
01156       default:
01157          ast_log(LOG_WARNING, "Huh (%d)?\n", action);       return -1;
01158       }
01159    } else if (sw) {
01160       switch(action) {
01161       case HELPER_CANMATCH:
01162          ast_mutex_unlock(&conlock);
01163          return -1;
01164       case HELPER_EXISTS:
01165          ast_mutex_unlock(&conlock);
01166          return -1;
01167       case HELPER_MATCHMORE:
01168          ast_mutex_unlock(&conlock);
01169          return -1;
01170       case HELPER_SPAWN:
01171          newstack++;
01172          /* Fall through */
01173       case HELPER_EXEC:
01174          ast_mutex_unlock(&conlock);
01175          if (sw->exec)
01176             res = sw->exec(c, context, exten, priority, callerid, newstack, data);
01177          else {
01178             ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
01179             res = -1;
01180          }
01181          return res;
01182       default:
01183          ast_log(LOG_WARNING, "Huh (%d)?\n", action);
01184          return -1;
01185       }
01186    } else {
01187       ast_mutex_unlock(&conlock);
01188       switch(status) {
01189       case STATUS_NO_CONTEXT:
01190          if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
01191             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
01192          break;
01193       case STATUS_NO_EXTENSION:
01194          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01195             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
01196          break;
01197       case STATUS_NO_PRIORITY:
01198          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01199             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
01200          break;
01201       default:
01202          ast_log(LOG_DEBUG, "Shouldn't happen!\n");
01203       }
01204       if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01205          return -1;
01206       else
01207          return 0;
01208    }
01209 
01210 }
01211 
01212 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
01213 {
01214    struct ast_exten *e;
01215    struct ast_switch *sw;
01216    char *data;
01217    int status = 0;
01218    char *incstack[AST_PBX_MAX_STACK];
01219    int stacklen = 0;
01220 
01221    if (ast_mutex_lock(&conlock)) {
01222       ast_log(LOG_WARNING, "Unable to obtain lock\n");
01223       return NULL;
01224    }
01225    e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
01226    ast_mutex_unlock(&conlock);   
01227    return e;
01228 }
01229 
01230 static int ast_extension_state2(struct ast_exten *e)
01231 {
01232     char hint[AST_MAX_EXTENSION] = "";    
01233     char *cur, *rest;
01234     int res = -1;
01235     int allunavailable = 1, allbusy = 1, allfree = 1;
01236     int busy = 0;
01237 
01238     strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
01239     
01240     cur = hint;    
01241     do {
01242    rest = strchr(cur, '&');
01243    if (rest) {
01244        *rest = 0;
01245        rest++;
01246    }
01247    
01248    res = ast_device_state(cur);
01249    switch (res) {
01250     case AST_DEVICE_NOT_INUSE:
01251       allunavailable = 0;
01252       allbusy = 0;
01253       break;
01254     case AST_DEVICE_INUSE:
01255       return AST_EXTENSION_INUSE;
01256     case AST_DEVICE_BUSY:
01257       allunavailable = 0;
01258       allfree = 0;
01259       busy = 1;
01260       break;
01261     case AST_DEVICE_UNAVAILABLE:
01262     case AST_DEVICE_INVALID:
01263       allbusy = 0;
01264       allfree = 0;
01265       break;
01266     default:
01267       allunavailable = 0;
01268       allbusy = 0;
01269       allfree = 0;
01270    }
01271         cur = rest;
01272     } while (cur);
01273 
01274     if (allfree)
01275       return AST_EXTENSION_NOT_INUSE;
01276     if (allbusy)
01277       return AST_EXTENSION_BUSY;
01278     if (allunavailable)
01279       return AST_EXTENSION_UNAVAILABLE;
01280     if (busy) 
01281       return AST_EXTENSION_INUSE;
01282    
01283     return AST_EXTENSION_NOT_INUSE;
01284 }
01285 
01286 
01287 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
01288 {
01289     struct ast_exten *e;
01290 
01291     e = ast_hint_extension(c, context, exten);    
01292     if (!e) 
01293    return -1;
01294 
01295     return ast_extension_state2(e);    
01296 }
01297 
01298 int ast_device_state_changed(const char *fmt, ...) 
01299 {
01300     struct ast_hint *list;
01301     struct ast_state_cb *cblist;
01302     char hint[AST_MAX_EXTENSION];
01303     char device[AST_MAX_EXTENSION];
01304     char *cur, *rest;
01305     int state;
01306     
01307     va_list ap;
01308 
01309     va_start(ap, fmt);
01310     vsnprintf(device, sizeof(device)-1, fmt, ap);
01311     va_end(ap);
01312 
01313     rest = strchr(device, '-');
01314     if (rest) {
01315    *rest = 0;
01316     }
01317         
01318     ast_mutex_lock(&hintlock);
01319 
01320     list = hints;
01321     
01322     while (list) {
01323    
01324    strcpy(hint, ast_get_extension_app(list->exten));
01325    cur = hint;
01326    do {
01327        rest = strchr(cur, '&');
01328        if (rest) {
01329       *rest = 0;
01330       rest++;
01331        }
01332        
01333        if (!strcmp(cur, device)) {
01334        // Found extension execute callbacks 
01335       state = ast_extension_state2(list->exten);
01336       if ((state != -1) && (state != list->laststate)) {
01337           // For general callbacks
01338           cblist = statecbs;
01339           while (cblist) {
01340          cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
01341          cblist = cblist->next;
01342           }
01343           
01344           // For extension callbacks
01345              cblist = list->callbacks;
01346           while (cblist) {
01347          cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
01348          cblist = cblist->next;
01349           }
01350           
01351           list->laststate = state;
01352       }
01353       break;
01354        }
01355        cur = rest;
01356    } while (cur);
01357    
01358    list = list->next;
01359     }
01360 
01361     ast_mutex_unlock(&hintlock);
01362     return 1;
01363 }
01364          
01365 int ast_extension_state_add(char *context, char *exten, 
01366              ast_state_cb_type callback, void *data)
01367 {
01368     struct ast_hint *list;
01369     struct ast_state_cb *cblist;
01370     struct ast_exten *e;
01371 
01372     /* No context and extension add callback to statecbs list */
01373     if (!context && !exten) {
01374    ast_mutex_lock(&hintlock);
01375 
01376    cblist = statecbs;
01377    while (cblist) {
01378        if (cblist->callback == callback) {
01379       cblist->data = data;
01380       ast_mutex_unlock(&hintlock);
01381        }
01382        
01383        cblist = cblist->next;
01384    }
01385    
01386    /* Now inserts the callback */
01387    cblist = malloc(sizeof(struct ast_state_cb));
01388    if (!cblist) {
01389        ast_mutex_unlock(&hintlock);
01390        return -1;
01391    }
01392    memset(cblist, 0, sizeof(struct ast_state_cb));
01393    cblist->id = 0;
01394    cblist->callback = callback;
01395    cblist->data = data;
01396 
01397         cblist->next = statecbs;
01398    statecbs = cblist;
01399 
01400    ast_mutex_unlock(&hintlock);
01401    return 0;
01402     }
01403 
01404     if (!context || !exten)
01405    return -1;
01406 
01407     /* This callback type is for only one hint */
01408     e = ast_hint_extension(NULL, context, exten);    
01409     if (!e) {
01410         return -1;
01411     }
01412     
01413     ast_mutex_lock(&hintlock);
01414     list = hints;        
01415     
01416     while (list) {
01417    if (list->exten == e)
01418        break;      
01419    list = list->next;    
01420     }
01421 
01422     if (!list) {
01423    ast_mutex_unlock(&hintlock);
01424    return -1;
01425     }
01426 
01427     /* Now inserts the callback */
01428     cblist = malloc(sizeof(struct ast_state_cb));
01429     if (!cblist) {
01430    ast_mutex_unlock(&hintlock);
01431    return -1;
01432     }
01433     memset(cblist, 0, sizeof(struct ast_state_cb));
01434     cblist->id = stateid++;
01435     cblist->callback = callback;
01436     cblist->data = data;
01437 
01438     cblist->next = list->callbacks;
01439     list->callbacks = cblist;
01440 
01441     ast_mutex_unlock(&hintlock);
01442     return cblist->id;
01443 }
01444 
01445 int ast_extension_state_del(int id, ast_state_cb_type callback)
01446 {
01447     struct ast_hint *list;
01448     struct ast_state_cb *cblist, *cbprev;
01449     
01450     if (!id && !callback)
01451    return -1;
01452             
01453     ast_mutex_lock(&hintlock);
01454 
01455     /* id is zero is a callback without extension */
01456     if (!id) {
01457    cbprev = NULL;
01458    cblist = statecbs;
01459    while (cblist) {
01460        if (cblist->callback == callback) {
01461       if (!cbprev)
01462           statecbs = cblist->next;
01463       else
01464           cbprev->next = cblist->next;
01465 
01466       free(cblist);
01467 
01468            ast_mutex_unlock(&hintlock);
01469       return 0;
01470        }
01471        cbprev = cblist;
01472        cblist = cblist->next;
01473    }
01474 
01475         ast_mutex_lock(&hintlock);
01476    return -1;
01477     }
01478 
01479     /* id greater zero is a callback with extension */
01480     list = hints;
01481     while (list) {
01482    cblist = list->callbacks;
01483    cbprev = NULL;
01484    while (cblist) {
01485        if (cblist->id==id) {
01486       if (!cbprev)
01487           list->callbacks = cblist->next;    
01488       else
01489           cbprev->next = cblist->next;
01490       
01491       free(cblist);
01492       
01493       ast_mutex_unlock(&hintlock);
01494       return 0;      
01495        }    
01496           cbprev = cblist;          
01497        cblist = cblist->next;
01498    }
01499    list = list->next;
01500     }
01501     
01502     ast_mutex_unlock(&hintlock);
01503     return -1;
01504 }
01505 
01506 static int ast_add_hint(struct ast_exten *e)
01507 {
01508     struct ast_hint *list;
01509 
01510     if (!e) return -1;
01511     
01512     ast_mutex_lock(&hintlock);
01513     list = hints;        
01514     
01515     /* Search if hint exists, do nothing */
01516     while (list) {
01517    if (list->exten == e) {
01518        ast_mutex_unlock(&hintlock);
01519        return -1;
01520    }
01521    list = list->next;    
01522     }
01523 
01524     list = malloc(sizeof(struct ast_hint));
01525     if (!list) {
01526    ast_mutex_unlock(&hintlock);
01527    return -1;
01528     }
01529     /* Initialize and insert new item */
01530     memset(list, 0, sizeof(struct ast_hint));
01531     list->exten = e;
01532     list->laststate = ast_extension_state2(e);
01533     list->next = hints;
01534     hints = list;
01535 
01536     ast_mutex_unlock(&hintlock);
01537     return 0;
01538 }
01539 
01540 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
01541 { 
01542     struct ast_hint *list;
01543 
01544     ast_mutex_lock(&hintlock);
01545     
01546     list = hints;
01547     
01548     while(list) {
01549    if (list->exten == oe) {
01550        list->exten = ne;
01551        ast_mutex_unlock(&hintlock); 
01552        return 0;
01553    }
01554    list = list->next;
01555     }
01556     ast_mutex_unlock(&hintlock);
01557 
01558     return -1;
01559 }
01560 
01561 static int ast_remove_hint(struct ast_exten *e)
01562 {
01563     /* Cleanup the Notifys if hint is removed */
01564     struct ast_hint *list, *prev = NULL;
01565     struct ast_state_cb *cblist, *cbprev;
01566 
01567     if (!e) 
01568    return -1;
01569 
01570     ast_mutex_lock(&hintlock);
01571 
01572     list = hints;    
01573     while(list) {
01574    if (list->exten==e) {
01575        cbprev = NULL;
01576        cblist = list->callbacks;
01577        while (cblist) {
01578       /* Notify with -1 and remove all callbacks */
01579       cbprev = cblist;      
01580       cblist = cblist->next;
01581       cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
01582       free(cbprev);
01583        }
01584        list->callbacks = NULL;
01585 
01586        if (!prev)
01587       hints = list->next;
01588        else
01589       prev->next = list->next;
01590 
01591        free(list);
01592        
01593        ast_mutex_unlock(&hintlock);
01594        return 0;
01595    } else {
01596        prev = list;
01597           list = list->next;    
01598    }
01599     }
01600 
01601     ast_mutex_unlock(&hintlock);
01602     return -1;
01603 }
01604 
01605 
01606 int ast_get_hint(char *hint, int maxlen, struct ast_channel *c, char *context, char *exten)
01607 {
01608    struct ast_exten *e;
01609    e = ast_hint_extension(c, context, exten);
01610    if (e) { 
01611        strncpy(hint, ast_get_extension_app(e), maxlen);
01612        return -1;
01613    }
01614    return 0;   
01615 }
01616 
01617 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
01618 {
01619    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
01620 }
01621 
01622 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
01623 {
01624    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
01625 }
01626 
01627 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
01628 {
01629    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
01630 }
01631 
01632 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
01633 {
01634    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
01635 }
01636 
01637 int ast_pbx_run(struct ast_channel *c)
01638 {
01639    int firstpass = 1;
01640    char digit;
01641    char exten[256];
01642    int pos;
01643    int waittime;
01644    int res=0;
01645 
01646    /* A little initial setup here */
01647    if (c->pbx)
01648       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
01649    c->pbx = malloc(sizeof(struct ast_pbx));
01650    if (!c->pbx) {
01651       ast_log(LOG_WARNING, "Out of memory\n");
01652       return -1;
01653    }
01654    if (c->amaflags) {
01655       if (c->cdr) {
01656          ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
01657       } else {
01658          c->cdr = ast_cdr_alloc();
01659          if (!c->cdr) {
01660             ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01661             free(c->pbx);
01662             return -1;
01663          }
01664          ast_cdr_init(c->cdr, c);
01665       }
01666    }
01667    memset(c->pbx, 0, sizeof(struct ast_pbx));
01668    /* Set reasonable defaults */
01669    c->pbx->rtimeout = 10;
01670    c->pbx->dtimeout = 5;
01671 
01672    /* Start by trying whatever the channel is set to */
01673    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01674       /* JK02: If not successfull fall back to 's' */
01675       strncpy(c->exten, "s", sizeof(c->exten)-1);
01676       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01677          /* JK02: And finally back to default if everything else failed */
01678          strncpy(c->context, "default", sizeof(c->context)-1);
01679       }
01680       c->priority = 1;
01681    }
01682    if (c->cdr)
01683       ast_cdr_start(c->cdr);
01684    for(;;) {
01685       pos = 0;
01686       digit = 0;
01687       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01688          memset(exten, 0, sizeof(exten));
01689          manager_event(EVENT_FLAG_CALL, "Newexten", 
01690             "Channel: %s\r\n"
01691             "Context: %s\r\n"
01692             "Extension: %s\r\n"
01693             "Priority: %d\r\n"
01694             "Uniqueid: %s\r\n",
01695             c->name, c->context, c->exten, c->priority, c->uniqueid);
01696          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
01697             /* Something bad happened, or a hangup has been requested. */
01698             if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
01699                (res == '*') || (res == '#')) {
01700                ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
01701                memset(exten, 0, sizeof(exten));
01702                pos = 0;
01703                exten[pos++] = digit = res;
01704                break;
01705             }
01706             switch(res) {
01707             case AST_PBX_KEEPALIVE:
01708                if (option_debug)
01709                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
01710                else if (option_verbose > 1)
01711                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
01712                goto out;
01713                break;
01714             default:
01715                if (option_debug)
01716                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01717                else if (option_verbose > 1)
01718                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01719                if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
01720                   c->_softhangup =0;
01721                   break;
01722                }
01723                /* atimeout */
01724                if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
01725                   break;
01726                }
01727                goto out;
01728             }
01729          }
01730          if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
01731             strncpy(c->exten,"T",sizeof(c->exten) - 1);
01732             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
01733             c->whentohangup = 0;
01734             c->priority = 0;
01735             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
01736          } else if (c->_softhangup) {
01737             ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
01738                c->exten, c->priority);
01739             goto out;
01740          }
01741          firstpass = 0;
01742          c->priority++;
01743       }
01744       if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
01745          /* It's not a valid extension anymore */
01746          if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
01747             if (option_verbose > 2)
01748                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
01749             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
01750             strncpy(c->exten, "i", sizeof(c->exten)-1);
01751             c->priority = 1;
01752          } else {
01753             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
01754                c->name, c->exten, c->context);
01755             goto out;
01756          }
01757       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
01758          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
01759          c->_softhangup = 0;
01760       } else {
01761          /* Done, wait for an extension */
01762          if (digit)
01763             waittime = c->pbx->dtimeout;
01764          else
01765             waittime = c->pbx->rtimeout;
01766          while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
01767             /* As long as we're willing to wait, and as long as it's not defined, 
01768                keep reading digits until we can't possibly get a right answer anymore.  */
01769             digit = ast_waitfordigit(c, waittime * 1000);
01770             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
01771                c->_softhangup = 0;
01772             } else {
01773                if (!digit)
01774                   /* No entry */
01775                   break;
01776                if (digit < 0)
01777                   /* Error, maybe a  hangup */
01778                   goto out;
01779                exten[pos++] = digit;
01780                waittime = c->pbx->dtimeout;
01781             }
01782          }
01783          if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
01784             /* Prepare the next cycle */
01785             strncpy(c->exten, exten, sizeof(c->exten)-1);
01786             c->priority = 1;
01787          } else {
01788             /* No such extension */
01789             if (strlen(exten)) {
01790                /* An invalid extension */
01791                if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
01792                   if (option_verbose > 2)
01793                      ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
01794                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
01795                   strncpy(c->exten, "i", sizeof(c->exten)-1);
01796                   c->priority = 1;
01797                } else {
01798                   ast_log(LOG_WARNING, "Invalid extension, but no rule 'i' in context '%s'\n", c->context);
01799                   goto out;
01800                }
01801             } else {
01802                /* A simple timeout */
01803                if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
01804                   if (option_verbose > 2)
01805                      ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
01806                   strncpy(c->exten, "t", sizeof(c->exten)-1);
01807                   c->priority = 1;
01808                } else {
01809                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
01810                   goto out;
01811                }
01812             }  
01813          }
01814          if (c->cdr) {
01815              if (option_verbose > 2)
01816             ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);   
01817              ast_cdr_update(c);
01818           }
01819       }
01820    }
01821    if (firstpass) 
01822       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
01823 out:
01824    if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
01825       strcpy(c->exten, "h");
01826       c->priority = 1;
01827       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01828          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
01829             /* Something bad happened, or a hangup has been requested. */
01830             if (option_debug)
01831                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01832             else if (option_verbose > 1)
01833                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01834             break;
01835          }
01836          c->priority++;
01837       }
01838    }
01839 
01840    pbx_destroy(c->pbx);
01841    c->pbx = NULL;
01842    if (res != AST_PBX_KEEPALIVE)
01843       ast_hangup(c);
01844    return 0;
01845 }
01846 
01847 static void *pbx_thread(void *data)
01848 {
01849    /* Oh joyeous kernel, we're a new thread, with nothing to do but
01850       answer this channel and get it going.  The setjmp stuff is fairly
01851       confusing, but necessary to get smooth transitions between
01852       the execution of different applications (without the use of
01853       additional threads) */
01854    struct ast_channel *c = data;
01855    ast_pbx_run(c);
01856    pthread_exit(NULL);
01857    return NULL;
01858 }
01859 
01860 int ast_pbx_start(struct ast_channel *c)
01861 {
01862    pthread_t t;
01863    pthread_attr_t attr;
01864    if (!c) {
01865       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
01866       return -1;
01867    }
01868       
01869    /* Start a new thread, and get something handling this channel. */
01870    pthread_attr_init(&attr);
01871    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01872    if (pthread_create(&t, &attr, pbx_thread, c)) {
01873       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
01874       return -1;
01875    }
01876    return 0;
01877 }
01878 
01879 /*
01880  * This function locks contexts list by &conlist, search for the rigt context
01881  * structure, leave context list locked and call ast_context_remove_include2
01882  * which removes include, unlock contexts list and return ...
01883  */
01884 int ast_context_remove_include(char *context, char *include, char *registrar)
01885 {
01886    struct ast_context *c;
01887 
01888    if (ast_lock_contexts()) return -1;
01889 
01890    /* walk contexts and search for the right one ...*/
01891    c = ast_walk_contexts(NULL);
01892    while (c) {
01893       /* we found one ... */
01894       if (!strcmp(ast_get_context_name(c), context)) {
01895          int ret;
01896          /* remove include from this context ... */   
01897          ret = ast_context_remove_include2(c, include, registrar);
01898 
01899          ast_unlock_contexts();
01900 
01901          /* ... return results */
01902          return ret;
01903       }
01904       c = ast_walk_contexts(c);
01905    }
01906 
01907    /* we can't find the right one context */
01908    ast_unlock_contexts();
01909    return -1;
01910 }
01911 
01912 /*
01913  * When we call this function, &conlock lock must be locked, because when
01914  * we giving *con argument, some process can remove/change this context
01915  * and after that there can be segfault.
01916  *
01917  * This function locks given context, removes include, unlock context and
01918  * return.
01919  */
01920 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
01921 {
01922    struct ast_include *i, *pi = NULL;
01923 
01924    if (ast_mutex_lock(&con->lock)) return -1;
01925 
01926    /* walk includes */
01927    i = con->includes;
01928    while (i) {
01929       /* find our include */
01930       if (!strcmp(i->name, include) && 
01931          (!strcmp(i->registrar, registrar) || !registrar)) {
01932          /* remove from list */
01933          if (pi)
01934             pi->next = i->next;
01935          else
01936             con->includes = i->next;
01937          /* free include and return */
01938          free(i);
01939          ast_mutex_unlock(&con->lock);
01940          return 0;
01941       }
01942       pi = i;
01943       i = i->next;
01944    }
01945 
01946    /* we can't find the right include */
01947    ast_mutex_unlock(&con->lock);
01948    return -1;
01949 }
01950 
01951 /*
01952  * This function locks contexts list by &conlist, search for the rigt context
01953  * structure, leave context list locked and call ast_context_remove_switch2
01954  * which removes switch, unlock contexts list and return ...
01955  */
01956 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
01957 {
01958    struct ast_context *c;
01959 
01960    if (ast_lock_contexts()) return -1;
01961 
01962    /* walk contexts and search for the right one ...*/
01963    c = ast_walk_contexts(NULL);
01964    while (c) {
01965       /* we found one ... */
01966       if (!strcmp(ast_get_context_name(c), context)) {
01967          int ret;
01968          /* remove switch from this context ... */ 
01969          ret = ast_context_remove_switch2(c, sw, data, registrar);
01970 
01971          ast_unlock_contexts();
01972 
01973          /* ... return results */
01974          return ret;
01975       }
01976       c = ast_walk_contexts(c);
01977    }
01978 
01979    /* we can't find the right one context */
01980    ast_unlock_contexts();
01981    return -1;
01982 }
01983 
01984 /*
01985  * When we call this function, &conlock lock must be locked, because when
01986  * we giving *con argument, some process can remove/change this context
01987  * and after that there can be segfault.
01988  *
01989  * This function locks given context, removes switch, unlock context and
01990  * return.
01991  */
01992 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
01993 {
01994    struct ast_sw *i, *pi = NULL;
01995 
01996    if (ast_mutex_lock(&con->lock)) return -1;
01997 
01998    /* walk switchs */
01999    i = con->alts;
02000    while (i) {
02001       /* find our switch */
02002       if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
02003          (!strcmp(i->registrar, registrar) || !registrar)) {
02004          /* remove from list */
02005          if (pi)
02006             pi->next = i->next;
02007          else
02008             con->alts = i->next;
02009          /* free switch and return */
02010          free(i);
02011          ast_mutex_unlock(&con->lock);
02012          return 0;
02013       }
02014       pi = i;
02015       i = i->next;
02016    }
02017 
02018    /* we can't find the right switch */
02019    ast_mutex_unlock(&con->lock);
02020    return -1;
02021 }
02022 
02023 /*
02024  * This functions lock contexts list, search for the right context,
02025  * call ast_context_remove_extension2, unlock contexts list and return.
02026  * In this function we are using
02027  */
02028 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
02029 {
02030    struct ast_context *c;
02031 
02032    if (ast_lock_contexts()) return -1;
02033 
02034    /* walk contexts ... */
02035    c = ast_walk_contexts(NULL);
02036    while (c) {
02037       /* ... search for the right one ... */
02038       if (!strcmp(ast_get_context_name(c), context)) {
02039          /* ... remove extension ... */
02040          int ret = ast_context_remove_extension2(c, extension, priority,
02041             registrar);
02042          /* ... unlock contexts list and return */
02043          ast_unlock_contexts();
02044          return ret;
02045       }
02046       c = ast_walk_contexts(c);
02047    }
02048 
02049    /* we can't find the right context */
02050    ast_unlock_contexts();
02051    return -1;
02052 }
02053 
02054 /*
02055  * When do you want to call this function, make sure that &conlock is locked,
02056  * because some process can handle with your *con context before you lock
02057  * it.
02058  *
02059  * This functionc locks given context, search for the right extension and
02060  * fires out all peer in this extensions with given priority. If priority
02061  * is set to 0, all peers are removed. After that, unlock context and
02062  * return.
02063  */
02064 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
02065 {
02066    struct ast_exten *exten, *prev_exten = NULL;
02067 
02068    if (ast_mutex_lock(&con->lock)) return -1;
02069 
02070    /* go through all extensions in context and search the right one ... */
02071    exten = con->root;
02072    while (exten) {
02073 
02074       /* look for right extension */
02075       if (!strcmp(exten->exten, extension) &&
02076          (!strcmp(exten->registrar, registrar) || !registrar)) {
02077          struct ast_exten *peer;
02078 
02079          /* should we free all peers in this extension? (priority == 0)? */
02080          if (priority == 0) {
02081             /* remove this extension from context list */
02082             if (prev_exten)
02083                prev_exten->next = exten->next;
02084             else
02085                con->root = exten->next;
02086 
02087             /* fire out all peers */
02088             peer = exten; 
02089             while (peer) {
02090                exten = peer->peer;
02091                
02092                if (!peer->priority==PRIORITY_HINT) 
02093                    ast_remove_hint(peer);
02094 
02095                peer->datad(peer->data);
02096                free(peer);
02097 
02098                peer = exten;
02099             }
02100 
02101             ast_mutex_unlock(&con->lock);
02102             return 0;
02103          } else {
02104             /* remove only extension with exten->priority == priority */
02105             struct ast_exten *previous_peer = NULL;
02106 
02107             peer = exten;
02108             while (peer) {
02109                /* is this our extension? */
02110                if (peer->priority == priority &&
02111                   (!strcmp(peer->registrar, registrar) || !registrar)) {
02112                   /* we are first priority extension? */
02113                   if (!previous_peer) {
02114                      /* exists previous extension here? */
02115                      if (prev_exten) {
02116                         /* yes, so we must change next pointer in
02117                          * previous connection to next peer
02118                          */
02119                         if (peer->peer) {
02120                            prev_exten->next = peer->peer;
02121                            peer->peer->next = exten->next;
02122                         } else
02123                            prev_exten->next = exten->next;
02124                      } else {
02125                         /* no previous extension, we are first
02126                          * extension, so change con->root ...
02127                          */
02128                         if (peer->peer)
02129                            con->root = peer->peer;
02130                         else
02131                            con->root = exten->next; 
02132                      }
02133                   } else {
02134                      /* we are not first priority in extension */
02135                      previous_peer->peer = peer->peer;
02136                   }
02137 
02138                   /* now, free whole priority extension */
02139                   if (peer->priority==PRIORITY_HINT)
02140                       ast_remove_hint(peer);
02141                   peer->datad(peer->data);
02142                   free(peer);
02143 
02144                   ast_mutex_unlock(&con->lock);
02145                   return 0;
02146                } else {
02147                   /* this is not right extension, skip to next peer */
02148                   previous_peer = peer;
02149                   peer = peer->peer;
02150                }
02151             }
02152 
02153             ast_mutex_unlock(&con->lock);
02154             return -1;
02155          }
02156       }
02157 
02158       prev_exten = exten;
02159       exten = exten->next;
02160    }
02161 
02162    /* we can't find right extension */
02163    ast_mutex_unlock(&con->lock);
02164    return -1;
02165 }
02166 
02167 
02168 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
02169 {
02170    struct ast_app *tmp, *prev, *cur;
02171    char tmps[80];
02172    if (ast_mutex_lock(&applock)) {
02173       ast_log(LOG_ERROR, "Unable to lock application list\n");
02174       return -1;
02175    }
02176    tmp = apps;
02177    while(tmp) {
02178       if (!strcasecmp(app, tmp->name)) {
02179          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02180          ast_mutex_unlock(&applock);
02181          return -1;
02182       }
02183       tmp = tmp->next;
02184    }
02185    tmp = malloc(sizeof(struct ast_app));
02186    if (tmp) {
02187       memset(tmp, 0, sizeof(struct ast_app));
02188       strncpy(tmp->name, app, sizeof(tmp->name)-1);
02189       tmp->execute = execute;
02190       tmp->synopsis = synopsis;
02191       tmp->description = description;
02192       /* Store in alphabetical order */
02193       cur = apps;
02194       prev = NULL;
02195       while(cur) {
02196          if (strcasecmp(tmp->name, cur->name) < 0)
02197             break;
02198          prev = cur;
02199          cur = cur->next;
02200       }
02201       if (prev) {
02202          tmp->next = prev->next;
02203          prev->next = tmp;
02204       } else {
02205          tmp->next = apps;
02206          apps = tmp;
02207       }
02208    } else {
02209       ast_log(LOG_WARNING, "Out of memory\n");
02210       ast_mutex_unlock(&applock);
02211       return -1;
02212    }
02213    if (option_verbose > 1)
02214       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02215    ast_mutex_unlock(&applock);
02216    return 0;
02217 }
02218 
02219 int ast_register_switch(struct ast_switch *sw)
02220 {
02221    struct ast_switch *tmp, *prev=NULL;
02222    if (ast_mutex_lock(&switchlock)) {
02223       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02224       return -1;
02225    }
02226    tmp = switches;
02227    while(tmp) {
02228       if (!strcasecmp(tmp->name, sw->name))
02229          break;
02230       prev = tmp;
02231       tmp = tmp->next;
02232    }
02233    if (tmp) {  
02234       ast_mutex_unlock(&switchlock);
02235       ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
02236       return -1;
02237    }
02238    sw->next = NULL;
02239    if (prev) 
02240       prev->next = sw;
02241    else
02242       switches = sw;
02243    ast_mutex_unlock(&switchlock);
02244    return 0;
02245 }
02246 
02247 void ast_unregister_switch(struct ast_switch *sw)
02248 {
02249    struct ast_switch *tmp, *prev=NULL;
02250    if (ast_mutex_lock(&switchlock)) {
02251       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02252       return;
02253    }
02254    tmp = switches;
02255    while(tmp) {
02256       if (tmp == sw) {
02257          if (prev)
02258             prev->next = tmp->next;
02259          else
02260             switches = tmp->next;
02261          tmp->next = NULL;
02262          break;         
02263       }
02264       prev = tmp;
02265       tmp = tmp->next;
02266    }
02267    ast_mutex_unlock(&switchlock);
02268 }
02269 
02270 /*
02271  * Help for CLI commands ...
02272  */
02273 static char show_application_help[] = 
02274 "Usage: show application <application> [<application> [<application> [...]]]\n"
02275 "       Describes a particular application.\n";
02276 
02277 static char show_applications_help[] =
02278 "Usage: show applications\n"
02279 "       List applications which are currently available.\n";
02280 
02281 static char show_dialplan_help[] =
02282 "Usage: show dialplan [exten@][context]\n"
02283 "       Show dialplan\n";
02284 
02285 static char show_switches_help[] = 
02286 "Usage: show switches\n"
02287 "       Show registered switches\n";
02288 
02289 /*
02290  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
02291  *
02292  */
02293 
02294 /*
02295  * 'show application' CLI command implementation functions ...
02296  */
02297 
02298 /*
02299  * There is a possibility to show informations about more than one
02300  * application at one time. You can type 'show application Dial Echo' and
02301  * you will see informations about these two applications ...
02302  */
02303 static char *complete_show_application(char *line, char *word,
02304    int pos, int state)
02305 {
02306    struct ast_app *a;
02307    int which = 0;
02308 
02309    /* try to lock applications list ... */
02310    if (ast_mutex_lock(&applock)) {
02311       ast_log(LOG_ERROR, "Unable to lock application list\n");
02312       return NULL;
02313    }
02314 
02315    /* ... walk all applications ... */
02316    a = apps; 
02317    while (a) {
02318       /* ... check if word matches this application ... */
02319       if (!strncasecmp(word, a->name, strlen(word))) {
02320          /* ... if this is right app serve it ... */
02321          if (++which > state) {
02322             char *ret = strdup(a->name);
02323             ast_mutex_unlock(&applock);
02324             return ret;
02325          }
02326       }
02327       a = a->next; 
02328    }
02329 
02330    /* no application match */
02331    ast_mutex_unlock(&applock);
02332    return NULL; 
02333 }
02334 
02335 static int handle_show_application(int fd, int argc, char *argv[])
02336 {
02337    struct ast_app *a;
02338    char buf[2048];
02339    int app, no_registered_app = 1;
02340 
02341    if (argc < 3) return RESULT_SHOWUSAGE;
02342 
02343    /* try to lock applications list ... */
02344    if (ast_mutex_lock(&applock)) {
02345       ast_log(LOG_ERROR, "Unable to lock application list\n");
02346       return -1;
02347    }
02348 
02349    /* ... go through all applications ... */
02350    a = apps; 
02351    while (a) {
02352       /* ... compare this application name with all arguments given
02353        * to 'show application' command ... */
02354       for (app = 2; app < argc; app++) {
02355          if (!strcasecmp(a->name, argv[app])) {
02356             no_registered_app = 0;
02357 
02358             /* ... one of our applications, show info ...*/
02359             snprintf(buf, sizeof(buf),
02360                "\n  -= Info about application '%s' =- \n\n"
02361                "[Synopsis]:\n  %s\n\n"
02362                "[Description]:\n%s\n",
02363                a->name,
02364                a->synopsis ? a->synopsis : "Not available",
02365                a->description ? a-> description : "Not available");
02366             ast_cli(fd, buf);
02367          }
02368       }
02369       a = a->next; 
02370    }
02371 
02372    ast_mutex_unlock(&applock);
02373 
02374    /* we found at least one app? no? */
02375    if (no_registered_app) {
02376       ast_cli(fd, "Your application(s) is (are) not registered\n");
02377       return RESULT_FAILURE;
02378    }
02379 
02380    return RESULT_SUCCESS;
02381 }
02382 
02383 static int handle_show_switches(int fd, int argc, char *argv[])
02384 {
02385    struct ast_switch *sw;
02386    if (!switches) {
02387       ast_cli(fd, "There are no registered alternative switches\n");
02388       return RESULT_SUCCESS;
02389    }
02390    /* ... we have applications ... */
02391    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
02392    if (ast_mutex_lock(&switchlock)) {
02393       ast_log(LOG_ERROR, "Unable to lock switches\n");
02394       return -1;
02395    }
02396    sw = switches;
02397    while (sw) {
02398       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
02399       sw = sw->next;
02400    }
02401    ast_mutex_unlock(&switchlock);
02402    return RESULT_SUCCESS;
02403 }
02404 
02405 /*
02406  * 'show applications' CLI command implementation functions ...
02407  */
02408 static int handle_show_applications(int fd, int argc, char *argv[])
02409 {
02410    struct ast_app *a;
02411 
02412    /* try to lock applications list ... */
02413    if (ast_mutex_lock(&applock)) {
02414       ast_log(LOG_ERROR, "Unable to lock application list\n");
02415       return -1;
02416    }
02417 
02418    /* ... go to first application ... */
02419    a = apps; 
02420 
02421    /* ... have we got at least one application (first)? no? */
02422    if (!a) {
02423       ast_cli(fd, "There is no registered applications\n");
02424       ast_mutex_unlock(&applock);
02425       return -1;
02426    }
02427 
02428    /* ... we have applications ... */
02429    ast_cli(fd, "\n    -= Registered Asterisk Applications =-\n");
02430 
02431    /* ... go through all applications ... */
02432    while (a) {
02433       /* ... show informations about applications ... */
02434       ast_cli(fd,"  %15s: %s\n",
02435          a->name,
02436          a->synopsis ? a->synopsis : "<Synopsis not available>");
02437       a = a->next; 
02438    }
02439 
02440    /* ... unlock and return */
02441    ast_mutex_unlock(&applock);
02442 
02443    return RESULT_SUCCESS;
02444 }
02445 
02446 /*
02447  * 'show dialplan' CLI command implementation functions ...
02448  */
02449 static char *complete_show_dialplan_context(char *line, char *word, int pos,
02450    int state)
02451 {
02452    struct ast_context *c;
02453    int which = 0;
02454 
02455    /* we are do completion of [exten@]context on second position only */
02456    if (pos != 2) return NULL;
02457 
02458    /* try to lock contexts list ... */
02459    if (ast_lock_contexts()) {
02460       ast_log(LOG_ERROR, "Unable to lock context list\n");
02461       return NULL;
02462    }
02463 
02464    /* ... walk through all contexts ... */
02465    c = ast_walk_contexts(NULL);
02466    while(c) {
02467       /* ... word matches context name? yes? ... */
02468       if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
02469          /* ... for serve? ... */
02470          if (++which > state) {
02471             /* ... yes, serve this context name ... */
02472             char *ret = strdup(ast_get_context_name(c));
02473             ast_unlock_contexts();
02474             return ret;
02475          }
02476       }
02477       c = ast_walk_contexts(c);
02478    }
02479 
02480    /* ... unlock and return */
02481    ast_unlock_contexts();
02482    return NULL;
02483 }
02484 
02485 static int handle_show_dialplan(int fd, int argc, char *argv[])
02486 {
02487    struct ast_context *c;
02488    char *exten = NULL, *context = NULL;
02489    int context_existence = 0, extension_existence = 0;
02490 
02491    if (argc != 3 && argc != 2) return -1;
02492 
02493    /* we obtain [exten@]context? if yes, split them ... */
02494    if (argc == 3) {
02495       char *splitter = argv[2];
02496       /* is there a '@' character? */
02497       if (strchr(argv[2], '@')) {
02498          /* yes, split into exten & context ... */
02499          exten   = strsep(&splitter, "@");
02500          context = splitter;
02501 
02502          /* check for length and change to NULL if !strlen() */
02503          if (!strlen(exten))   exten = NULL;
02504          if (!strlen(context)) context = NULL;
02505       } else
02506       {
02507          /* no '@' char, only context given */
02508          context = argv[2];
02509          if (!strlen(context)) context = NULL;
02510       }
02511    }
02512 
02513    /* try to lock contexts */
02514    if (ast_lock_contexts()) {
02515       ast_cli(LOG_WARNING, "Failed to lock contexts list\n");
02516       return RESULT_FAILURE;
02517    }
02518 
02519    /* walk all contexts ... */
02520    c = ast_walk_contexts(NULL);
02521    while (c) {
02522       /* show this context? */
02523       if (!context ||
02524          !strcmp(ast_get_context_name(c), context)) {
02525          context_existence = 1;
02526 
02527          /* try to lock context before walking in ... */
02528          if (!ast_lock_context(c)) {
02529             struct ast_exten *e;
02530             struct ast_include *i;
02531             struct ast_ignorepat *ip;
02532             struct ast_sw *sw;
02533             char buf[256], buf2[256];
02534             int context_info_printed = 0;
02535 
02536             /* are we looking for exten too? if yes, we print context
02537              * if we our extension only
02538              */
02539             if (!exten) {
02540                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
02541                   ast_get_context_name(c), ast_get_context_registrar(c));
02542                context_info_printed = 1;
02543             }
02544 
02545             /* walk extensions ... */
02546             e = ast_walk_context_extensions(c, NULL);
02547             while (e) {
02548                struct ast_exten *p;
02549 
02550                /* looking for extension? is this our extension? */
02551                if (exten &&
02552                   strcmp(ast_get_extension_name(e), exten))
02553                {
02554                   /* we are looking for extension and it's not our
02555                    * extension, so skip to next extension */
02556                   e = ast_walk_context_extensions(c, e);
02557                   continue;
02558                }
02559 
02560                extension_existence = 1;
02561 
02562                /* may we print context info? */ 
02563                if (!context_info_printed) {
02564                   ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
02565                      ast_get_context_name(c),
02566                      ast_get_context_registrar(c));
02567                   context_info_printed = 1;
02568                }
02569 
02570                /* write extension name and first peer */ 
02571                bzero(buf, sizeof(buf));      
02572                snprintf(buf, sizeof(buf), "'%s' =>",
02573                   ast_get_extension_name(e));
02574 
02575                snprintf(buf2, sizeof(buf2),
02576                   "%d. %s(%s)",
02577                   ast_get_extension_priority(e),
02578                   ast_get_extension_app(e),
02579                   (char *)ast_get_extension_app_data(e));
02580 
02581                ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
02582                   ast_get_extension_registrar(e));
02583 
02584                /* walk next extension peers */
02585                p = ast_walk_extension_priorities(e, e);
02586                while (p) {
02587                   bzero((void *)buf2, sizeof(buf2));
02588 
02589                   snprintf(buf2, sizeof(buf2),
02590                      "%d. %s(%s)",
02591                      ast_get_extension_priority(p),
02592                      ast_get_extension_app(p),
02593                      (char *)ast_get_extension_app_data(p));
02594 
02595                   ast_cli(fd,"  %-17s %-45s [%s]\n",
02596                      "", buf2,
02597                      ast_get_extension_registrar(p)); 
02598 
02599                   p = ast_walk_extension_priorities(e, p);
02600                }
02601                e = ast_walk_context_extensions(c, e);
02602             }
02603 
02604             /* include & ignorepat we all printing if we are not
02605              * looking for exact extension
02606              */
02607             if (!exten) {
02608                if (ast_walk_context_extensions(c, NULL))
02609                   ast_cli(fd, "\n");
02610 
02611                /* walk included and write info ... */
02612                i = ast_walk_context_includes(c, NULL);
02613                while (i) {
02614                   bzero(buf, sizeof(buf));
02615                   snprintf(buf, sizeof(buf), "'%s'",
02616                      ast_get_include_name(i));
02617                   ast_cli(fd, "  Include =>        %-45s [%s]\n",
02618                      buf, ast_get_include_registrar(i));
02619                   i = ast_walk_context_includes(c, i);
02620                }
02621 
02622                /* walk ignore patterns and write info ... */
02623                ip = ast_walk_context_ignorepats(c, NULL);
02624                while (ip) {
02625                   bzero(buf, sizeof(buf));
02626                   snprintf(buf, sizeof(buf), "'%s'",
02627                      ast_get_ignorepat_name(ip));
02628                   ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
02629                      buf, ast_get_ignorepat_registrar(ip)); 
02630                   ip = ast_walk_context_ignorepats(c, ip);
02631                }
02632                sw = ast_walk_context_switches(c, NULL);
02633                while(sw) {
02634                   bzero(buf, sizeof(buf));
02635                   snprintf(buf, sizeof(buf), "'%s/%s'",
02636                      ast_get_switch_name(sw),
02637                      ast_get_switch_data(sw));
02638                   ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
02639                      buf, ast_get_switch_registrar(sw)); 
02640                   sw = ast_walk_context_switches(c, sw);
02641                }
02642             }
02643    
02644             ast_unlock_context(c);
02645 
02646             /* if we print something in context, make an empty line */
02647             if (context_info_printed) ast_cli(fd, "\n");
02648          }
02649       }
02650       c = ast_walk_contexts(c);
02651    }
02652    ast_unlock_contexts();
02653 
02654    /* check for input failure and throw some error messages */
02655    if (context && !context_existence) {
02656       ast_cli(fd, "There is no existence of '%s' context\n",
02657          context);
02658       return RESULT_FAILURE;
02659    }
02660 
02661    if (exten && !extension_existence) {
02662       if (context)
02663          ast_cli(fd, "There is no existence of %s@%s extension\n",
02664             exten, context);
02665       else
02666          ast_cli(fd,
02667             "There is no existence of '%s' extension in all contexts\n",
02668             exten);
02669       return RESULT_FAILURE;
02670    }
02671 
02672    /* everything ok */
02673    return RESULT_SUCCESS;
02674 }
02675 
02676 /*
02677  * CLI entries for upper commands ...
02678  */
02679 static struct ast_cli_entry show_applications_cli = 
02680    { { "show", "applications", NULL }, 
02681    handle_show_applications, "Shows registered applications",
02682    show_applications_help };
02683 
02684 static struct ast_cli_entry show_application_cli =
02685    { { "show", "application", NULL }, 
02686    handle_show_application, "Describe a specific application",
02687    show_application_help, complete_show_application };
02688 
02689 static struct ast_cli_entry show_dialplan_cli =
02690    { { "show", "dialplan", NULL },
02691       handle_show_dialplan, "Show dialplan",
02692       show_dialplan_help, complete_show_dialplan_context };
02693 
02694 static struct ast_cli_entry show_switches_cli =
02695    { { "show", "switches", NULL },
02696       handle_show_switches, "Show alternative switches",
02697       show_switches_help, NULL };
02698 
02699 int ast_unregister_application(char *app) {
02700    struct ast_app *tmp, *tmpl = NULL;
02701    if (ast_mutex_lock(&applock)) {
02702       ast_log(LOG_ERROR, "Unable to lock application list\n");
02703       return -1;
02704    }
02705    tmp = apps;
02706    while(tmp) {
02707       if (!strcasecmp(app, tmp->name)) {
02708          if (tmpl)
02709             tmpl->next = tmp->next;
02710          else
02711             apps = tmp->next;
02712          if (option_verbose > 1)
02713             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
02714          ast_mutex_unlock(&applock);
02715          return 0;
02716       }
02717       tmpl = tmp;
02718       tmp = tmp->next;
02719    }
02720    ast_mutex_unlock(&applock);
02721    return -1;
02722 }
02723 
02724 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
02725 {
02726    struct ast_context *tmp, **local_contexts;
02727    if (!extcontexts) {
02728       local_contexts = &contexts;
02729       ast_mutex_lock(&conlock);
02730    } else
02731       local_contexts = extcontexts;
02732 
02733    tmp = *local_contexts;
02734    while(tmp) {
02735       if (!strcasecmp(tmp->name, name)) {
02736          ast_mutex_unlock(&conlock);
02737          ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
02738          if (!extcontexts)
02739             ast_mutex_unlock(&conlock);
02740          return NULL;
02741       }
02742       tmp = tmp->next;
02743    }
02744    tmp = malloc(sizeof(struct ast_context));
02745    if (tmp) {
02746       memset(tmp, 0, sizeof(struct ast_context));
02747       ast_mutex_init(&tmp->lock);
02748       strncpy(tmp->name, name, sizeof(tmp->name)-1);
02749       tmp->root = NULL;
02750       tmp->registrar = registrar;
02751       tmp->next = *local_contexts;
02752       tmp->includes = NULL;
02753       tmp->ignorepats = NULL;
02754       *local_contexts = tmp;
02755       if (option_debug)
02756          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
02757       else if (option_verbose > 2)
02758          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
02759    } else
02760       ast_log(LOG_WARNING, "Out of memory\n");
02761    
02762    if (!extcontexts)
02763       ast_mutex_unlock(&conlock);
02764    return tmp;
02765 }
02766 
02767 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock);
02768 
02769 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
02770    struct ast_context *tmp, *lasttmp = NULL;
02771    tmp = *extcontexts;
02772    ast_mutex_lock(&conlock);
02773    if (registrar) {
02774       __ast_context_destroy(NULL,registrar,0);
02775       while (tmp) {
02776          lasttmp = tmp;
02777          tmp = tmp->next;
02778       }
02779    } else {
02780       while (tmp) {
02781          __ast_context_destroy(tmp,tmp->registrar,0);
02782          lasttmp = tmp;
02783          tmp = tmp->next;
02784       }
02785    }
02786    if (lasttmp) {
02787       lasttmp->next = contexts;
02788       contexts = *extcontexts;
02789       *extcontexts = NULL;
02790    } else 
02791       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
02792    ast_mutex_unlock(&conlock);
02793    return;  
02794 }
02795 
02796 /*
02797  * errno values
02798  *  EBUSY  - can't lock
02799  *  ENOENT - no existence of context
02800  */
02801 int ast_context_add_include(char *context, char *include, char *registrar)
02802 {
02803    struct ast_context *c;
02804 
02805    if (ast_lock_contexts()) {
02806       errno = EBUSY;
02807       return -1;
02808    }
02809 
02810    /* walk contexts ... */
02811    c = ast_walk_contexts(NULL);
02812    while (c) {
02813       /* ... search for the right one ... */
02814       if (!strcmp(ast_get_context_name(c), context)) {
02815          int ret = ast_context_add_include2(c, include, registrar);
02816          /* ... unlock contexts list and return */
02817          ast_unlock_contexts();
02818          return ret;
02819       }
02820       c = ast_walk_contexts(c);
02821    }
02822 
02823    /* we can't find the right context */
02824    ast_unlock_contexts();
02825    errno = ENOENT;
02826    return -1;
02827 }
02828 
02829 #define FIND_NEXT \
02830 do { \
02831    c = info; \
02832    while(*c && (*c != '|')) c++; \
02833    if (*c) { *c = '\0'; c++; } else c = NULL; \
02834 } while(0)
02835 
02836 static void get_timerange(struct ast_include *i, char *times)
02837 {
02838    char *e;
02839    int x;
02840    int s1, s2;
02841    int e1, e2;
02842 
02843    //[PHM 07/01/03]
02844    //start disabling all times, fill the fields with 0's, as they may contain garbage
02845    memset(i->minmask, 0, sizeof(i->minmask));
02846    
02847    /* Star is all times */
02848    if (!strlen(times) || !strcmp(times, "*")) {
02849       for (x=0;x<24;x++)
02850          i->minmask[x] = (1 << 30) - 1;
02851       return;
02852    }
02853    /* Otherwise expect a range */
02854    e = strchr(times, '-');
02855    if (!e) {
02856       ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
02857       return;
02858    }
02859    *e = '\0';
02860    e++;
02861    while(*e && !isdigit(*e)) e++;
02862    if (!*e) {
02863       ast_log(LOG_WARNING, "Invalid time range.  Assuming no time.\n");
02864       return;
02865    }
02866    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
02867       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", times);
02868       return;
02869    }
02870    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
02871       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", e);
02872       return;
02873    }
02874    s1 = s1 * 30 + s2/2;
02875    if ((s1 < 0) || (s1 >= 24*30)) {
02876       ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
02877       return;
02878    }
02879    e1 = e1 * 30 + e2/2;
02880    if ((e1 < 0) || (e2 >= 24*30)) {
02881       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
02882       return;
02883    }
02884    /* Go through the time and enable each appropriate bit */
02885    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
02886       i->minmask[x/30] |= (1 << (x % 30));
02887    }
02888    /* Do the last one */
02889    i->minmask[x/30] |= (1 << (x % 30));
02890    /* All done */
02891    return;
02892 }
02893 
02894 static char *days[] =
02895 {
02896    "sun",
02897    "mon",
02898    "tue",
02899    "wed",
02900    "thu",
02901    "fri",
02902    "sat",
02903 };
02904 
02905 static unsigned int get_dow(char *dow)
02906 {
02907    char *c;
02908    /* The following line is coincidence, really! */
02909    int s, e, x;
02910    unsigned int mask;
02911    /* Check for all days */
02912    if (!strlen(dow) || !strcmp(dow, "*"))
02913       return (1 << 7) - 1;
02914    /* Get start and ending days */
02915    c = strchr(dow, '-');
02916    if (c) {
02917       *c = '\0';
02918       c++;
02919    } else
02920       c = NULL;
02921    /* Find the start */
02922    s = 0;
02923    while((s < 7) && strcasecmp(dow, days[s])) s++;
02924    if (s >= 7) {
02925       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
02926       return 0;
02927    }
02928    if (c) {
02929       e = 0;
02930       while((e < 7) && strcasecmp(c, days[e])) e++;
02931       if (e >= 7) {
02932          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
02933          return 0;
02934       }
02935    } else
02936       e = s;
02937    mask = 0;
02938    for (x=s;x!=e;x = (x + 1) % 7) {
02939       mask |= (1 << x);
02940    }
02941    /* One last one */
02942    mask |= (1 << x);
02943    return mask;
02944 }
02945 
02946 static unsigned int get_day(char *day)
02947 {
02948    char *c;
02949    /* The following line is coincidence, really! */
02950    int s, e, x;
02951    unsigned int mask;
02952    /* Check for all days */
02953    if (!strlen(day) || !strcmp(day, "*")) {
02954       mask = (1 << 30)  + ((1 << 30) - 1);
02955       return mask;
02956    }
02957    /* Get start and ending days */
02958    c = strchr(day, '-');
02959    if (c) {
02960       *c = '\0';
02961       c++;
02962    }
02963    /* Find the start */
02964    if (sscanf(day, "%d", &s) != 1) {
02965       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
02966       return 0;
02967    }
02968    if ((s < 1) || (s > 31)) {
02969       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
02970       return 0;
02971    }
02972    s--;
02973    if (c) {
02974       if (sscanf(c, "%d", &e) != 1) {
02975          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
02976          return 0;
02977       }
02978       if ((e < 1) || (e > 31)) {
02979          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
02980          return 0;
02981       }
02982       e--;
02983    } else
02984       e = s;
02985    mask = 0;
02986    for (x=s;x!=e;x = (x + 1) % 31) {
02987       mask |= (1 << x);
02988    }
02989    mask |= (1 << x);
02990    return mask;
02991 }
02992 
02993 static char *months[] =
02994 {
02995    "jan",
02996    "feb",
02997    "mar",
02998    "apr",
02999    "may",
03000    "jun",
03001    "jul",
03002    "aug",
03003    "sep",
03004    "oct",
03005    "nov",
03006    "dec",
03007 };
03008 
03009 static unsigned int get_month(char *mon)
03010 {
03011    char *c;
03012    /* The following line is coincidence, really! */
03013    int s, e, x;
03014    unsigned int mask;
03015    /* Check for all days */
03016    if (!strlen(mon) || !strcmp(mon, "*")) 
03017       return (1 << 12) - 1;
03018    /* Get start and ending days */
03019    c = strchr(mon, '-');
03020    if (c) {
03021       *c = '\0';
03022       c++;
03023    }
03024    /* Find the start */
03025    s = 0;
03026    while((s < 12) && strcasecmp(mon, months[s])) s++;
03027    if (s >= 12) {
03028       ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
03029       return 0;
03030    }
03031    if (c) {
03032       e = 0;
03033       while((e < 12) && strcasecmp(mon, months[e])) e++;
03034       if (e >= 12) {
03035          ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
03036          return 0;
03037       }
03038    } else
03039       e = s;
03040    mask = 0;
03041    for (x=s;x!=e;x = (x + 1) % 12) {
03042       mask |= (1 << x);
03043    }
03044    /* One last one */
03045    mask |= (1 << x);
03046    return mask;
03047 }
03048 
03049 static void build_timing(struct ast_include *i, char *info)
03050 {
03051    char *c;
03052    /* Check for empty just in case */
03053    if (!strlen(info))
03054       return;
03055    i->hastime = 1;
03056    /* Assume everything except time */
03057    i->monthmask = (1 << 12) - 1;
03058    i->daymask = (1 << 30) - 1 + (1 << 30);
03059    i->dowmask = (1 << 7) - 1;
03060    /* Avoid using str tok */
03061    FIND_NEXT;
03062    /* Info has the time range, start with that */
03063    get_timerange(i, info);
03064    info = c;
03065    if (!info)
03066       return;
03067    FIND_NEXT;
03068    /* Now check for day of week */
03069    i->dowmask = get_dow(info);
03070 
03071    info = c;
03072    if (!info)
03073       return;
03074    FIND_NEXT;
03075    /* Now check for the day of the month */
03076    i->daymask = get_day(info);
03077    info = c;
03078    if (!info)
03079       return;
03080    FIND_NEXT;
03081    /* And finally go for the month */
03082    i->monthmask = get_month(info);
03083 }
03084 
03085 /*
03086  * errno values
03087  *  ENOMEM - out of memory
03088  *  EBUSY  - can't lock
03089  *  EEXIST - already included
03090  *  EINVAL - there is no existence of context for inclusion
03091  */
03092 int ast_context_add_include2(struct ast_context *con, char *value,
03093    char *registrar)
03094 {
03095    struct ast_include *new_include;
03096    char *c;
03097    struct ast_include *i, *il = NULL; /* include, include_last */
03098 
03099    /* allocate new include structure ... */
03100    if (!(new_include = malloc(sizeof(struct ast_include)))) {
03101       ast_log(LOG_WARNING, "Out of memory\n");
03102       errno = ENOMEM;
03103       return -1;
03104    }
03105    
03106    /* ... fill in this structure ... */
03107    memset(new_include, 0, sizeof(struct ast_include));
03108    strncpy(new_include->name, value, sizeof(new_include->name)-1);
03109    strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
03110    c = new_include->rname;
03111    /* Strip off timing info */
03112    while(*c && (*c != '|')) c++; 
03113    /* Process if it's there */
03114    if (*c) {
03115       build_timing(new_include, c+1);
03116       *c = '\0';
03117    }
03118    new_include->next      = NULL;
03119    new_include->registrar = registrar;
03120 
03121    /* ... try to lock this context ... */
03122    if (ast_mutex_lock(&con->lock)) {
03123       free(new_include);
03124       errno = EBUSY;
03125       return -1;
03126    }
03127 
03128    /* ... go to last include and check if context is already included too... */
03129    i = con->includes;
03130    while (i) {
03131       if (!strcasecmp(i->name, new_include->name)) {
03132          free(new_include);
03133          ast_mutex_unlock(&con->lock);
03134          errno = EEXIST;
03135          return -1;
03136       }
03137       il = i;
03138       i = i->next;
03139    }
03140 
03141    /* ... include new context into context list, unlock, return */
03142    if (il)
03143       il->next = new_include;
03144    else
03145       con->includes = new_include;
03146    if (option_verbose > 2)
03147       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 
03148    ast_mutex_unlock(&con->lock);
03149 
03150    return 0;
03151 }
03152 
03153 /*
03154  * errno values
03155  *  EBUSY  - can't lock
03156  *  ENOENT - no existence of context
03157  */
03158 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
03159 {
03160    struct ast_context *c;
03161 
03162    if (ast_lock_contexts()) {
03163       errno = EBUSY;
03164       return -1;
03165    }
03166 
03167    /* walk contexts ... */
03168    c = ast_walk_contexts(NULL);
03169    while (c) {
03170       /* ... search for the right one ... */
03171       if (!strcmp(ast_get_context_name(c), context)) {
03172          int ret = ast_context_add_switch2(c, sw, data, registrar);
03173          /* ... unlock contexts list and return */
03174          ast_unlock_contexts();
03175          return ret;
03176       }
03177       c = ast_walk_contexts(c);
03178    }
03179 
03180    /* we can't find the right context */
03181    ast_unlock_contexts();
03182    errno = ENOENT;
03183    return -1;
03184 }
03185 
03186 /*
03187  * errno values
03188  *  ENOMEM - out of memory
03189  *  EBUSY  - can't lock
03190  *  EEXIST - already included
03191  *  EINVAL - there is no existence of context for inclusion
03192  */
03193 int ast_context_add_switch2(struct ast_context *con, char *value,
03194    char *data, char *registrar)
03195 {
03196    struct ast_sw *new_sw;
03197    struct ast_sw *i, *il = NULL; /* sw, sw_last */
03198 
03199    /* allocate new sw structure ... */
03200    if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
03201       ast_log(LOG_WARNING, "Out of memory\n");
03202       errno = ENOMEM;
03203       return -1;
03204    }
03205    
03206    /* ... fill in this structure ... */
03207    memset(new_sw, 0, sizeof(struct ast_sw));
03208    strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
03209    if (data)
03210       strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
03211    else
03212       strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
03213    new_sw->next      = NULL;
03214    new_sw->registrar = registrar;
03215 
03216    /* ... try to lock this context ... */
03217    if (ast_mutex_lock(&con->lock)) {
03218       free(new_sw);
03219       errno = EBUSY;
03220       return -1;
03221    }
03222 
03223    /* ... go to last sw and check if context is already swd too... */
03224    i = con->alts;
03225    while (i) {
03226       if (!strcasecmp(i->name, new_sw->name)) {
03227          free(new_sw);
03228          ast_mutex_unlock(&con->lock);
03229          errno = EEXIST;
03230          return -1;
03231       }
03232       il = i;
03233       i = i->next;
03234    }
03235 
03236    /* ... sw new context into context list, unlock, return */
03237    if (il)
03238       il->next = new_sw;
03239    else
03240       con->alts = new_sw;
03241    if (option_verbose > 2)
03242       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 
03243    ast_mutex_unlock(&con->lock);
03244 
03245    return 0;
03246 }
03247 
03248 /*
03249  * EBUSY  - can't lock
03250  * ENOENT - there is not context existence
03251  */
03252 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
03253 {
03254    struct ast_context *c;
03255 
03256    if (ast_lock_contexts()) {
03257       errno = EBUSY;
03258       return -1;
03259    }
03260 
03261    c = ast_walk_contexts(NULL);
03262    while (c) {
03263       if (!strcmp(ast_get_context_name(c), context)) {
03264          int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
03265          ast_unlock_contexts();
03266          return ret;
03267       }
03268       c = ast_walk_contexts(c);
03269    }
03270 
03271    ast_unlock_contexts();
03272    errno = ENOENT;
03273    return -1;
03274 }
03275 
03276 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
03277 {
03278    struct ast_ignorepat *ip, *ipl = NULL;
03279 
03280    if (ast_mutex_lock(&con->lock)) {
03281       errno = EBUSY;
03282       return -1;
03283    }
03284 
03285    ip = con->ignorepats;
03286    while (ip) {
03287       if (!strcmp(ip->pattern, ignorepat) &&
03288          (registrar == ip->registrar || !registrar)) {
03289          if (ipl) {
03290             ipl->next = ip->next;
03291             free(ip);
03292          } else {
03293             con->ignorepats = ip->next;
03294             free(ip);
03295          }
03296          ast_mutex_unlock(&con->lock);
03297          return 0;
03298       }
03299       ipl = ip; ip = ip->next;
03300    }
03301 
03302    ast_mutex_unlock(&con->lock);
03303    errno = EINVAL;
03304    return -1;
03305 }
03306 
03307 /*
03308  * EBUSY - can't lock
03309  * ENOENT - there is no existence of context
03310  */
03311 int ast_context_add_ignorepat(char *con, char *value, char *registrar)
03312 {
03313    struct ast_context *c;
03314 
03315    if (ast_lock_contexts()) {
03316       errno = EBUSY;
03317       return -1;
03318    }
03319 
03320    c = ast_walk_contexts(NULL);
03321    while (c) {
03322       if (!strcmp(ast_get_context_name(c), con)) {
03323          int ret = ast_context_add_ignorepat2(c, value, registrar);
03324          ast_unlock_contexts();
03325          return ret;
03326       } 
03327       c = ast_walk_contexts(c);
03328    }
03329 
03330    ast_unlock_contexts();
03331    errno = ENOENT;
03332    return -1;
03333 }
03334 
03335 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
03336 {
03337    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
03338    ignorepat = malloc(sizeof(struct ast_ignorepat));
03339    if (!ignorepat) {
03340       ast_log(LOG_WARNING, "Out of memory\n");
03341       errno = ENOMEM;
03342       return -1;
03343    }
03344    memset(ignorepat, 0, sizeof(struct ast_ignorepat));
03345    strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
03346    ignorepat->next = NULL;
03347    ignorepat->registrar = registrar;
03348    ast_mutex_lock(&con->lock);
03349    ignorepatc = con->ignorepats;
03350    while(ignorepatc) {
03351       ignorepatl = ignorepatc;
03352       if (!strcasecmp(ignorepatc->pattern, value)) {
03353          /* Already there */
03354          ast_mutex_unlock(&con->lock);
03355          errno = EEXIST;
03356          return -1;
03357       }
03358       ignorepatc = ignorepatc->next;
03359    }
03360    if (ignorepatl) 
03361       ignorepatl->next = ignorepat;
03362    else
03363       con->ignorepats = ignorepat;
03364    ast_mutex_unlock(&con->lock);
03365    return 0;
03366    
03367 }
03368 
03369 int ast_ignore_pattern(char *context, char *pattern)
03370 {
03371    struct ast_context *con;
03372    struct ast_ignorepat *pat;
03373    con = ast_context_find(context);
03374    if (con) {
03375       pat = con->ignorepats;
03376       while (pat) {
03377          if (ast_extension_match(pat->pattern, pattern))
03378             return 1;
03379          pat = pat->next;
03380       }
03381    } 
03382    return 0;
03383 }
03384 
03385 /*
03386  * EBUSY   - can't lock
03387  * ENOENT  - no existence of context
03388  *
03389  */
03390 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
03391    char *application, void *data, void (*datad)(void *), char *registrar)
03392 {
03393    struct ast_context *c;
03394 
03395    if (ast_lock_contexts()) {
03396       errno = EBUSY;
03397       return -1;
03398    }
03399 
03400    c = ast_walk_contexts(NULL);
03401    while (c) {
03402       if (!strcmp(context, ast_get_context_name(c))) {
03403          int ret = ast_add_extension2(c, replace, extension, priority, callerid,
03404             application, data, datad, registrar);
03405          ast_unlock_contexts();
03406          return ret;
03407       }
03408       c = ast_walk_contexts(c);
03409    }
03410 
03411    ast_unlock_contexts();
03412    errno = ENOENT;
03413    return -1;
03414 }
03415 
03416 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority, int needlock)
03417 {
03418    int res = 0;
03419    if (needlock)
03420       ast_mutex_lock(&chan->lock);
03421    if (chan->pbx) {
03422       /* This channel is currently in the PBX */
03423       if (context && strlen(context))
03424          strncpy(chan->context, context, sizeof(chan->context) - 1);
03425       if (exten && strlen(exten))
03426          strncpy(chan->exten, exten, sizeof(chan->context) - 1);
03427       if (priority)
03428          chan->priority = priority - 1;
03429       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
03430       if (needlock)
03431          ast_mutex_unlock(&chan->lock);
03432    } else {
03433       /* In order to do it when the channel doesn't really exist within
03434          the PBX, we have to make a new channel, masquerade, and start the PBX
03435          at the new location */
03436       struct ast_channel *tmpchan;
03437       struct ast_frame *f;
03438       tmpchan = ast_channel_alloc(0);
03439       if (tmpchan) {
03440          snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
03441          ast_setstate(tmpchan, chan->_state);
03442          /* Make formats okay */
03443          tmpchan->readformat = chan->readformat;
03444          tmpchan->writeformat = chan->writeformat;
03445          /* Setup proper location */
03446          if (context && strlen(context))
03447             strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
03448          else
03449             strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
03450          if (exten && strlen(exten))
03451             strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
03452          else
03453             strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
03454          if (priority)
03455             tmpchan->priority = priority;
03456          else
03457             tmpchan->priority = chan->priority;
03458          if (needlock)
03459             ast_mutex_unlock(&chan->lock);
03460          
03461          /* Masquerade into temp channel */
03462          ast_channel_masquerade(tmpchan, chan);
03463          
03464          /* Make the masquerade happen by reading a frame from the tmp channel */
03465          f = ast_read(tmpchan);
03466          if (f)
03467             ast_frfree(f);
03468          /* Start the PBX going on our stolen channel */
03469          if (ast_pbx_start(tmpchan)) {
03470             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
03471             ast_hangup(tmpchan);
03472             res = -1;
03473          }
03474       } else {
03475          res = -1;
03476          if (needlock)
03477             ast_mutex_unlock(&chan->lock);
03478       }
03479    }
03480    return res;
03481 }
03482 
03483 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
03484 {
03485    struct ast_channel *chan;
03486    chan = ast_channel_walk(NULL);
03487    while(chan) {
03488       if (!strcasecmp(channame, chan->name))
03489          break;
03490       chan = ast_channel_walk(chan);
03491    }
03492    if (chan)
03493       return ast_async_goto(chan, context, exten, priority, 1);
03494    return -1;
03495 }
03496 
03497 static void ext_strncpy(char *dst, char *src, int len)
03498 {
03499    int count=0;
03500    while(*src && (count < len - 1)) {
03501       switch(*src) {
03502       case ' ':
03503 //otherwise exten => [a-b],1,... doesn't work
03504 //    case '-':
03505          /* Ignore */
03506          break;
03507       default:
03508          *dst = *src;
03509          dst++;
03510       }
03511       src++;
03512       count++;
03513    }
03514    *dst = '\0';
03515 }
03516 
03517 /*
03518  * EBUSY - can't lock
03519  * EEXIST - extension with the same priority exist and no replace is set
03520  *
03521  */
03522 int ast_add_extension2(struct ast_context *con,
03523                  int replace, char *extension, int priority, char *callerid,
03524                  char *application, void *data, void (*datad)(void *),
03525                  char *registrar)
03526 {
03527 
03528 #define LOG do {  if (option_debug) {\
03529       if (tmp->matchcid) { \
03530          ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
03531       } else { \
03532          ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
03533       } \
03534    } else if (option_verbose > 2) { \
03535       if (tmp->matchcid) { \
03536          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
03537       } else {  \
03538          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
03539       } \
03540    } } while(0)
03541 
03542    /*
03543     * This is a fairly complex routine.  Different extensions are kept
03544     * in order by the extension number.  Then, extensions of different
03545     * priorities (same extension) are kept in a list, according to the
03546     * peer pointer.
03547     */
03548    struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
03549    int res;
03550    /* Be optimistic:  Build the extension structure first */
03551    tmp = malloc(sizeof(struct ast_exten));
03552    if (tmp) {
03553       memset(tmp, 0, sizeof(struct ast_exten));
03554       ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
03555       tmp->priority = priority;
03556       if (callerid) {
03557          ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
03558          tmp->matchcid = 1;
03559       } else {
03560          strcpy(tmp->cidmatch, "");
03561          tmp->matchcid = 0;
03562       }
03563       strncpy(tmp->app, application, sizeof(tmp->app)-1);
03564       tmp->parent = con;
03565       tmp->data = data;
03566       tmp->datad = datad;
03567       tmp->registrar = registrar;
03568       tmp->peer = NULL;
03569       tmp->next =  NULL;
03570    } else {
03571       ast_log(LOG_WARNING, "Out of memory\n");
03572       errno = ENOMEM;
03573       return -1;
03574    }
03575    if (ast_mutex_lock(&con->lock)) {
03576       free(tmp);
03577       /* And properly destroy the data */
03578       datad(data);
03579       ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
03580       errno = EBUSY;
03581       return -1;
03582    }
03583    e = con->root;
03584    while(e) {
03585       res= strcasecmp(e->exten, extension);
03586       if (!res) {
03587          if (!e->matchcid && !tmp->matchcid)
03588             res = 0;
03589          else if (tmp->matchcid && !e->matchcid)
03590             res = 1;
03591          else if (e->matchcid && !tmp->matchcid)
03592             res = -1;
03593          else
03594             res = strcasecmp(e->cidmatch, tmp->cidmatch);
03595       }
03596       if (res == 0) {
03597          /* We have an exact match, now we find where we are
03598             and be sure there's no duplicates */
03599          while(e) {
03600             if (e->priority == tmp->priority) {
03601                /* Can't have something exactly the same.  Is this a
03602                   replacement?  If so, replace, otherwise, bonk. */
03603                if (replace) {
03604                   if (ep) {
03605                      /* We're in the peer list, insert ourselves */
03606                      ep->peer = tmp;
03607                      tmp->peer = e->peer;
03608                   } else if (el) {
03609                      /* We're the first extension. Take over e's functions */
03610                      el->next = tmp;
03611                      tmp->next = e->next;
03612                      tmp->peer = e->peer;
03613                   } else {
03614                      /* We're the very first extension.  */
03615                      con->root = tmp;
03616                      tmp->next = e->next;
03617                      tmp->peer = e->peer;
03618                   }
03619                   if (tmp->priority == PRIORITY_HINT)
03620                       ast_change_hint(e,tmp);
03621                   /* Destroy the old one */
03622                   e->datad(e->data);
03623                   free(e);
03624                   ast_mutex_unlock(&con->lock);
03625                   if (tmp->priority == PRIORITY_HINT)
03626                       ast_change_hint(e, tmp);
03627                   /* And immediately return success. */
03628                   LOG;
03629                   return 0;
03630                } else {
03631                   ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
03632                   tmp->datad(tmp->data);
03633                   free(tmp);
03634                   ast_mutex_unlock(&con->lock);
03635                   errno = EEXIST;
03636                   return -1;
03637                }
03638             } else if (e->priority > tmp->priority) {
03639                /* Slip ourselves in just before e */
03640                if (ep) {
03641                   /* Easy enough, we're just in the peer list */
03642                   ep->peer = tmp;
03643                   tmp->peer = e;
03644                } else if (el) {
03645                   /* We're the first extension in this peer list */
03646                   el->next = tmp;
03647                   tmp->next = e->next;
03648                   e->next = NULL;
03649                   tmp->peer = e;
03650                } else {
03651                   /* We're the very first extension altogether */
03652                   tmp->next = con->root;
03653                   /* Con->root must always exist or we couldn't get here */
03654                   tmp->peer = con->root->peer;
03655                   con->root = tmp;
03656                }
03657                ast_mutex_unlock(&con->lock);
03658                /* And immediately return success. */
03659                if (tmp->priority == PRIORITY_HINT)
03660                    ast_add_hint(tmp);
03661                
03662                LOG;
03663                return 0;
03664             }
03665             ep = e;
03666             e = e->peer;
03667          }
03668          /* If we make it here, then it's time for us to go at the very end.
03669             ep *must* be defined or we couldn't have gotten here. */
03670          ep->peer = tmp;
03671          ast_mutex_unlock(&con->lock);
03672          if (tmp->priority == PRIORITY_HINT)
03673              ast_add_hint(tmp);
03674          
03675          /* And immediately return success. */
03676          LOG;
03677          return 0;
03678             
03679       } else if (res > 0) {
03680          /* Insert ourselves just before 'e'.  We're the first extension of
03681             this kind */
03682          tmp->next = e;
03683          if (el) {
03684             /* We're in the list somewhere */
03685             el->next = tmp;
03686          } else {
03687             /* We're at the top of the list */
03688             con->root = tmp;
03689          }
03690          ast_mutex_unlock(&con->lock);
03691          if (tmp->priority == PRIORITY_HINT)
03692              ast_add_hint(tmp);
03693 
03694          /* And immediately return success. */
03695          LOG;
03696          return 0;
03697       }        
03698          
03699       el = e;
03700       e = e->next;
03701    }
03702    /* If we fall all the way through to here, then we need to be on the end. */
03703    if (el)
03704       el->next = tmp;
03705    else
03706       con->root = tmp;
03707    ast_mutex_unlock(&con->lock);
03708    if (tmp->priority == PRIORITY_HINT)
03709        ast_add_hint(tmp);
03710    LOG;
03711    return 0;   
03712 }
03713 
03714 struct async_stat {
03715    pthread_t p;
03716    struct ast_channel *chan;
03717    char context[AST_MAX_EXTENSION];
03718    char exten[AST_MAX_EXTENSION];
03719    int priority;
03720    int timeout;
03721    char app[AST_MAX_EXTENSION];
03722    char appdata[1024];
03723 };
03724 
03725 static void *async_wait(void *data) 
03726 {
03727    struct async_stat *as = data;
03728    struct ast_channel *chan = as->chan;
03729    int timeout = as->timeout;
03730    int res;
03731    struct ast_frame *f;
03732    struct ast_app *app;
03733    
03734    while(timeout && (chan->_state != AST_STATE_UP)) {
03735       res = ast_waitfor(chan, timeout);
03736       if (res < 1) 
03737          break;
03738       if (timeout > -1)
03739          timeout = res;
03740       f = ast_read(chan);
03741       if (!f)
03742          break;
03743       if (f->frametype == AST_FRAME_CONTROL) {
03744          if ((f->subclass == AST_CONTROL_BUSY)  ||
03745             (f->subclass == AST_CONTROL_CONGESTION) )
03746                break;
03747       }
03748       ast_frfree(f);
03749    }
03750    if (chan->_state == AST_STATE_UP) {
03751       if (strlen(as->app)) {
03752          app = pbx_findapp(as->app);
03753          if (app) {
03754             if (option_verbose > 2)
03755                ast_verbose(VERBOSE_PREFIX_3 "Lauching %s(%s) on %s\n", as->app, as->appdata, chan->name);
03756             pbx_exec(chan, app, as->appdata, 1);
03757          } else
03758             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
03759       } else {
03760          if (strlen(as->context))
03761             strncpy(chan->context, as->context, sizeof(chan->context) - 1);
03762          if (strlen(as->exten))
03763             strncpy(chan->exten, as->exten, sizeof(chan->exten) - 1);
03764          if (as->priority > 0)
03765             chan->priority = as->priority;
03766          /* Run the PBX */
03767          if (ast_pbx_run(chan)) {
03768             ast_log(LOG_WARNING, "Failed to start PBX on %s\n", chan->name);
03769          } else {
03770             /* PBX will have taken care of this */
03771             chan = NULL;
03772          }
03773       }
03774          
03775    }
03776    free(as);
03777    if (chan)
03778       ast_hangup(chan);
03779    return NULL;
03780 }
03781 
03782 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 )
03783 {
03784    struct ast_channel *chan;
03785    struct async_stat *as;
03786    int res = -1;
03787    char *var, *tmp;
03788    if (sync) {
03789       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
03790       if (chan) {
03791          /* JDG chanvar */
03792          tmp = variable;
03793          /* FIXME replace this call with strsep  NOT*/
03794          while( (var = strtok_r(NULL, "|", &tmp)) ) {
03795             pbx_builtin_setvar( chan, var );
03796          } /* /JDG */
03797          if (chan->_state == AST_STATE_UP) {
03798             res = 0;
03799             if (option_verbose > 3)
03800                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
03801             if (context && strlen(context))
03802                strncpy(chan->context, context, sizeof(chan->context) - 1);
03803             if (exten && strlen(exten))
03804                strncpy(chan->exten, exten, sizeof(chan->exten) - 1);
03805             if (callerid && strlen(callerid))
03806                strncpy(chan->callerid, callerid, sizeof(chan->callerid) - 1);
03807             if (priority > 0)
03808                chan->priority = priority;
03809             if (sync > 1) {
03810                if (ast_pbx_run(chan)) {
03811                   ast_log(LOG_WARNING, "Unable to run PBX on %s\n", chan->name);
03812                   ast_hangup(chan);
03813                   res = -1;
03814                }
03815             } else {
03816                if (ast_pbx_start(chan)) {
03817                   ast_log(LOG_WARNING, "Unable to start PBX on %s\n", chan->name);
03818                   ast_hangup(chan);
03819                   res = -1;
03820                } 
03821             }
03822          } else {
03823             if (option_verbose > 3)
03824                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
03825             ast_hangup(chan);
03826          }
03827       }
03828    } else {
03829       as = malloc(sizeof(struct async_stat));
03830       if (!as)
03831          return -1;
03832       memset(as, 0, sizeof(struct async_stat));
03833       chan = ast_request_and_dial(type, format, data, 0, reason, callerid);
03834       if (!chan) {
03835          free(as);
03836          return -1;
03837       }
03838       as->chan = chan;
03839       strncpy(as->context, context, sizeof(as->context) - 1);
03840       strncpy(as->exten,  exten, sizeof(as->exten) - 1);
03841       as->priority = priority;
03842       as->timeout = timeout;
03843       if (pthread_create(&as->p, NULL, async_wait, as)) {
03844          ast_log(LOG_WARNING, "Failed to start async wait\n");
03845          free(as);
03846          ast_hangup(chan);
03847          return -1;
03848       }
03849       res = 0;
03850    }
03851    return res;
03852 }
03853 
03854 struct app_tmp {
03855    char app[256];
03856    char data[256];
03857    struct ast_channel *chan;
03858    pthread_t t;
03859 };
03860 
03861 static void *ast_pbx_run_app(void *data)
03862 {
03863    struct app_tmp *tmp = data;
03864    struct ast_app *app;
03865    app = pbx_findapp(tmp->app);
03866    if (app) {
03867       if (option_verbose > 3)
03868          ast_verbose(VERBOSE_PREFIX_4 "Lauching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
03869       pbx_exec(tmp->chan, app, tmp->data, 1);
03870    } else
03871       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
03872    ast_hangup(tmp->chan);
03873    free(tmp);
03874    return NULL;
03875 }
03876 
03877 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)
03878 {
03879    struct ast_channel *chan;
03880    struct async_stat *as;
03881    struct app_tmp *tmp;
03882    char *var, *vartmp;
03883    int res = -1;
03884    if (!app || !strlen(app))
03885       return -1;
03886    if (sync) {
03887       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
03888       if (chan) {
03889          vartmp = variable;
03890          while( (var = strtok_r(NULL, "|", &vartmp)) ) {
03891             pbx_builtin_setvar( chan, var );
03892          }
03893          if (chan->_state == AST_STATE_UP) {
03894             res = 0;
03895             if (option_verbose > 3)
03896                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
03897             tmp = malloc(sizeof(struct app_tmp));
03898             if (tmp) {
03899                memset(tmp, 0, sizeof(struct app_tmp));
03900                strncpy(tmp->app, app, sizeof(tmp->app) - 1);
03901                strncpy(tmp->data, appdata, sizeof(tmp->data) - 1);
03902                tmp->chan = chan;
03903                if (sync > 1) {
03904                   ast_pbx_run_app(tmp);
03905                } else {
03906                   if (pthread_create(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
03907                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
03908                      free(tmp);
03909                      ast_hangup(chan);
03910                      res = -1;
03911                   }
03912                }
03913             } else {
03914                ast_log(LOG_WARNING, "Out of memory :(\n");
03915                res = -1;
03916             }
03917          } else {
03918             if (option_verbose > 3)
03919                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
03920             ast_hangup(chan);
03921          }
03922       }
03923    } else {
03924       as = malloc(sizeof(struct async_stat));
03925       if (!as)
03926          return -1;
03927       memset(as, 0, sizeof(struct async_stat));
03928       chan = ast_request_and_dial(type, format, data, 0, reason, callerid);
03929       if (!chan) {
03930          free(as);
03931          return -1;
03932       }
03933       as->chan = chan;
03934       strncpy(as->app, app, sizeof(as->app) - 1);
03935       if (appdata)
03936          strncpy(as->appdata,  appdata, sizeof(as->appdata) - 1);
03937       as->timeout = timeout;
03938       if (pthread_create(&as->p, NULL, async_wait, as)) {
03939          ast_log(LOG_WARNING, "Failed to start async wait\n");
03940          free(as);
03941          ast_hangup(chan);
03942          return -1;
03943       }
03944       res = 0;
03945    }
03946    return res;
03947 }
03948 
03949 static void destroy_exten(struct ast_exten *e)
03950 {
03951    if (e->priority == PRIORITY_HINT)
03952       ast_remove_hint(e);
03953 
03954    if (e->datad)
03955       e->datad(e->data);
03956    free(e);
03957 }
03958 
03959 void __ast_context_destroy(struct ast_context *con, char *registrar, int lock)
03960 {
03961    struct ast_context *tmp, *tmpl=NULL;
03962    struct ast_include *tmpi, *tmpil= NULL;
03963    struct ast_sw *sw, *swl= NULL;
03964    struct ast_exten *e, *el, *en;
03965    if (lock)
03966       ast_mutex_lock(&conlock);
03967    tmp = contexts;
03968    while(tmp) {
03969       if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
03970           (!registrar || !strcasecmp(registrar, tmp->registrar))) {
03971          /* Okay, let's lock the structure to be sure nobody else
03972             is searching through it. */
03973          if (ast_mutex_lock(&tmp->lock)) {
03974             ast_log(LOG_WARNING, "Unable to lock context lock\n");
03975             return;
03976          }
03977          if (tmpl)
03978             tmpl->next = tmp->next;
03979          else
03980             contexts = tmp->next;
03981          /* Okay, now we're safe to let it go -- in a sense, we were
03982             ready to let it go as soon as we locked it. */
03983          ast_mutex_unlock(&tmp->lock);
03984          for (tmpi = tmp->includes; tmpi; ) {
03985             /* Free includes */
03986             tmpil = tmpi;
03987             tmpi = tmpi->next;
03988             free(tmpil);
03989             tmpil = tmpi;
03990          }
03991          for (sw = tmp->alts; sw; ) {
03992             swl = sw;
03993             sw = sw->next;
03994             free(swl);
03995             swl = sw;
03996          }
03997          for (e = tmp->root; e;) {
03998             for (en = e->peer; en;) {
03999                el = en;
04000                en = en->peer;
04001                destroy_exten(el);
04002             }
04003             el = e;
04004             e = e->next;
04005             destroy_exten(el);
04006          }
04007          free(tmp);
04008          if (!con) {
04009             /* Might need to get another one -- restart */
04010             tmp = contexts;
04011             tmpl = NULL;
04012             tmpil = NULL;
04013             continue;
04014          }
04015          if (lock)
04016             ast_mutex_unlock(&conlock);
04017          return;
04018       }
04019       tmpl = tmp;
04020       tmp = tmp->next;
04021    }
04022    if (lock)
04023       ast_mutex_unlock(&conlock);
04024 }
04025 
04026 void ast_context_destroy(struct ast_context *con, char *registrar)
04027 {
04028    __ast_context_destroy(con,registrar,1);
04029 }
04030 
04031 static void wait_for_hangup(struct ast_channel *chan)
04032 {
04033    int res;
04034    struct ast_frame *f;
04035    do {
04036       res = ast_waitfor(chan, -1);
04037       if (res < 0)
04038          return;
04039       f = ast_read(chan);
04040       if (f)
04041          ast_frfree(f);
04042    } while(f);
04043 }
04044 
04045 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
04046 {
04047    ast_indicate(chan, AST_CONTROL_RINGING);
04048    return 0;
04049 }
04050 
04051 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
04052 {
04053    ast_indicate(chan, AST_CONTROL_BUSY);     
04054    wait_for_hangup(chan);
04055    return -1;
04056 }
04057 
04058 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
04059 {
04060    ast_indicate(chan, AST_CONTROL_CONGESTION);
04061    wait_for_hangup(chan);
04062    return -1;
04063 }
04064 
04065 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
04066 {
04067    return ast_answer(chan);
04068 }
04069 
04070 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
04071 {
04072    /* Copy the language as specified */
04073    strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
04074    return 0;
04075 }
04076 
04077 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
04078 {
04079    /* Reset the CDR as specified */
04080    if (data)
04081       ast_cdr_reset(chan->cdr, strchr((char *)data, 'w') ? 1 : 0);
04082    else
04083       ast_cdr_reset(chan->cdr, 0);
04084    return 0;
04085 }
04086 
04087 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
04088 {
04089    /* Copy the language as specified */
04090    if (data)
04091       ast_cdr_setaccount(chan, (char *)data);
04092    else
04093       ast_cdr_setaccount(chan, "");
04094    return 0;
04095 }
04096 
04097 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
04098 {
04099    /* Just return non-zero and it will hang up */
04100    return -1;
04101 }
04102 
04103 static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
04104 {
04105    char newexten[AST_MAX_EXTENSION] = "";
04106    if (!data || !atoi(data)) {
04107       ast_log(LOG_DEBUG, "Ignoring, since number of digits to strip is 0\n");
04108       return 0;
04109    }
04110    if (strlen(chan->exten) > atoi(data)) {
04111       strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1);
04112    }
04113    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04114    return 0;
04115 }
04116 
04117 static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
04118 {
04119    char newexten[AST_MAX_EXTENSION] = "";
04120    if (!data || !strlen(data)) {
04121       ast_log(LOG_DEBUG, "Ignoring, since there is no prefix to add\n");
04122       return 0;
04123    }
04124    snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
04125    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04126    if (option_verbose > 2)
04127       ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
04128    return 0;
04129 }
04130 
04131 static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
04132 {
04133    char newexten[AST_MAX_EXTENSION] = "";
04134    if (!data || !strlen(data)) {
04135       ast_log(LOG_DEBUG, "Ignoring, since there is no suffix to add\n");
04136       return 0;
04137    }
04138    snprintf(newexten, sizeof(newexten), "%s%s", chan->exten, (char *)data);
04139    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04140    if (option_verbose > 2)
04141       ast_verbose(VERBOSE_PREFIX_3 "Appended suffix, new extension is %s\n", chan->exten);
04142    return 0;
04143 }
04144 
04145 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
04146 {
04147    int res=0;
04148    char *s, *ts;
04149    struct ast_include include;
04150 
04151    if (!data) {
04152       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
04153       return -1;
04154    }
04155 
04156    s = strdup((char *) data);
04157    ts = s;
04158 
04159    /* Separate the Goto path */
04160    strsep(&ts,"?");
04161 
04162    // [PHM 07/01/03]
04163    // struct ast_include include contained garbage here, fixed by zeroing it on get_timerange
04164    build_timing(&include, s);
04165    if (include_valid(&include))
04166       res = pbx_builtin_goto(chan, (void *)ts);
04167    free(s);
04168    return res;
04169 }
04170 
04171 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
04172 {
04173    int ms;
04174    /* Wait for "n" seconds */
04175    if (data && atoi((char *)data)) {
04176       ms = atoi((char *)data) * 1000;
04177       return ast_safe_sleep(chan, ms);
04178    }
04179    return 0;
04180 }
04181 
04182 static int pbx_builtin_background(struct ast_channel *chan, void *data)
04183 {
04184    int res;
04185    /* Answer if need be */
04186    if (chan->_state != AST_STATE_UP)
04187       if (ast_answer(chan))
04188          return -1;
04189    /* Stop anything playing */
04190    ast_stopstream(chan);
04191    /* Stream a file */
04192    res = ast_streamfile(chan, (char *)data, chan->language);
04193    if (!res) {
04194       res = ast_waitstream(chan, AST_DIGIT_ANY);
04195       ast_stopstream(chan);
04196    }
04197    return res;
04198 }
04199 
04200 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
04201 {
04202    int x = atoi((char *) data);
04203    /* Set the timeout for how long to wait between digits */
04204    ast_channel_setwhentohangup(chan,x);
04205    if (option_verbose > 2)
04206       ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
04207    return 0;
04208 }
04209 
04210 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
04211 {
04212    /* Set the timeout for how long to wait between digits */
04213    chan->pbx->rtimeout = atoi((char *)data);
04214    if (option_verbose > 2)
04215       ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
04216    return 0;
04217 }
04218 
04219 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
04220 {
04221    /* Set the timeout for how long to wait between digits */
04222    chan->pbx->dtimeout = atoi((char *)data);
04223    if (option_verbose > 2)
04224       ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
04225    return 0;
04226 }
04227 
04228 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
04229 {
04230    char *s;
04231    char *exten, *pri, *context;
04232    char *stringp=NULL;
04233    if (!data || !strlen(data)) {
04234       ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
04235       return -1;
04236    }
04237    s = strdup((void *) data);
04238    stringp=s;
04239    context = strsep(&stringp, "|");
04240    exten = strsep(&stringp, "|");
04241    if (!exten) {
04242       /* Only a priority in this one */
04243       pri = context;
04244       exten = NULL;
04245       context = NULL;
04246    } else {
04247       pri = strsep(&stringp, "|");
04248       if (!pri) {
04249          /* Only an extension and priority in this one */
04250          pri = exten;
04251          exten = context;
04252          context = NULL;
04253       }
04254    }
04255    if (atoi(pri) < 0) {
04256       ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
04257       free(s);
04258       return -1;
04259    }
04260    /* At this point we have a priority and maybe an extension and a context */
04261    chan->priority = atoi(pri) - 1;
04262    if (exten && strcasecmp(exten, "BYEXTENSION"))
04263       strncpy(chan->exten, exten, sizeof(chan->exten)-1);
04264    if (context)
04265       strncpy(chan->context, context, sizeof(chan->context)-1);
04266    if (option_verbose > 2)
04267       ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
04268    return 0;
04269 }
04270 
04271 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name) {
04272    struct ast_var_t *variables;
04273    struct varshead *headp;
04274 
04275     if (chan)
04276         headp=&chan->varshead;
04277    else
04278       headp=&globals;
04279 
04280    if (name) {
04281       AST_LIST_TRAVERSE(headp,variables,entries) {
04282          if (!strcmp(name, ast_var_name(variables)))
04283             return ast_var_value(variables);
04284       }
04285       if (headp != &globals) {
04286          /* Check global variables if we haven't already */
04287          headp = &globals;
04288          AST_LIST_TRAVERSE(headp,variables,entries) {
04289             if (!strcmp(name, ast_var_name(variables)))
04290                return ast_var_value(variables);
04291          }
04292       }
04293    }
04294    return NULL;
04295 }
04296 
04297 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value) {
04298    struct ast_var_t *newvariable;
04299         struct varshead *headp;
04300     if (chan)
04301         headp=&chan->varshead;
04302    else
04303       headp=&globals;
04304                 
04305    AST_LIST_TRAVERSE (headp,newvariable,entries) {
04306       if (strcasecmp(ast_var_name(newvariable),name)==0) {
04307          /* there is already such a variable, delete it */
04308          AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries);
04309          ast_var_delete(newvariable);
04310          break;
04311       }
04312    } 
04313    
04314    if (value) {
04315       if ((option_verbose > 1) && (headp == &globals))
04316          ast_verbose(VERBOSE_PREFIX_3 "Setting global variable '%s' to '%s'\n",name, value);
04317       newvariable=ast_var_assign(name,value);   
04318       AST_LIST_INSERT_HEAD(headp,newvariable,entries);
04319    }
04320 }
04321 
04322 static int pbx_builtin_setvar(struct ast_channel *chan, void *data)
04323 {
04324    char *name;
04325    char *value;
04326    char *stringp=NULL;
04327                 
04328    if (!data || !strlen(data)) {
04329       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04330       return 0;
04331    }
04332    
04333    stringp=data;
04334    name=strsep(&stringp,"=");
04335    value=strsep(&stringp,"\0"); 
04336    
04337    pbx_builtin_setvar_helper(chan,name,value);
04338          
04339         return(0);
04340 }
04341 
04342 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
04343 {
04344    char *name;
04345    char *value;
04346    char *stringp=NULL;
04347                 
04348    if (!data || !strlen(data)) {
04349       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04350       return 0;
04351    }
04352    
04353    stringp=data;
04354    name=strsep(&stringp,"=");
04355    value=strsep(&stringp,"\0"); 
04356    
04357    pbx_builtin_setvar_helper(NULL,name,value);
04358          
04359         return(0);
04360 }
04361 
04362 
04363 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
04364 {
04365    return 0;
04366 }
04367 
04368 
04369 void pbx_builtin_clear_globals(void)
04370 {
04371    struct ast_var_t *vardata;
04372    while (!AST_LIST_EMPTY(&globals)) {
04373       vardata = AST_LIST_FIRST(&globals);
04374       AST_LIST_REMOVE_HEAD(&globals, entries);
04375       ast_var_delete(vardata);
04376    }
04377 }
04378 
04379 static int pbx_checkcondition(char *condition) {
04380    char *s;
04381    int ret;
04382    
04383    s=strdup(condition);
04384    
04385    ret=1;
04386    
04387    if ((strcasecmp(s,"0")) || (strlen(s)==0)) {
04388       ret=0;
04389    }
04390    
04391    free(s);
04392    return(ret);
04393 }
04394 
04395 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
04396 {
04397    char *condition,*branch1,*branch2,*branch;
04398    char *s;
04399    int rc;
04400    char *stringp=NULL;
04401 
04402    if (!data || !strlen(data)) {
04403       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04404       return 0;
04405    }
04406    
04407    s=strdup(data);
04408    stringp=s;
04409    condition=strsep(&stringp,"?");
04410    branch1=strsep(&stringp,":");
04411    branch2=strsep(&stringp,"");
04412    
04413    if (pbx_checkcondition(condition)) {
04414       branch=branch2;
04415    } else {
04416       branch=branch1;
04417    }
04418    
04419    if ((branch==NULL) || (strlen(branch)==0)) {
04420       ast_log(LOG_WARNING, "Not taking any branch\n");
04421       return(0);
04422    }
04423    
04424    rc=pbx_builtin_goto(chan,branch);
04425    free(s);
04426    return(rc);
04427 }           
04428 
04429 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
04430 {
04431    int res = 0;
04432    if (data && atoi((char *)data) )
04433       res = ast_say_number(chan, atoi((char *)data), "", chan->language);
04434    return res;
04435 }
04436 
04437 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
04438 {
04439    int res = 0;
04440    if (data)
04441       res = ast_say_digit_str(chan, (char *)data, "", chan->language);
04442    return res;
04443 }
04444    
04445 int load_pbx(void)
04446 {
04447    int x;
04448    /* Initialize the PBX */
04449    if (option_verbose) {
04450       ast_verbose( "Asterisk PBX Core Initializing\n");
04451       ast_verbose( "Registering builtin applications:\n");
04452    }
04453    ast_cli_register(&show_applications_cli);
04454    ast_cli_register(&show_application_cli);
04455    ast_cli_register(&show_dialplan_cli);
04456    ast_cli_register(&show_switches_cli);
04457    for (x=0;x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
04458       if (option_verbose)
04459          ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
04460       if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
04461          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
04462          return -1;
04463       }
04464    }
04465    return 0;
04466 }
04467 
04468 /*
04469  * Lock context list functions ...
04470  */
04471 int ast_lock_contexts()
04472 {
04473    return ast_mutex_lock(&conlock);
04474 }
04475 
04476 int ast_unlock_contexts()
04477 {
04478    return ast_mutex_unlock(&conlock);
04479 }
04480 
04481 /*
04482  * Lock context ...
04483  */
04484 int ast_lock_context(struct ast_context *con)
04485 {
04486    return ast_mutex_lock(&con->lock);
04487 }
04488 
04489 int ast_unlock_context(struct ast_context *con)
04490 {
04491    return ast_mutex_unlock(&con->lock);
04492 }
04493 
04494 /*
04495  * Name functions ...
04496  */
04497 char *ast_get_context_name(struct ast_context *con)
04498 {
04499    return con ? con->name : NULL;
04500 }
04501 
04502 char *ast_get_extension_name(struct ast_exten *exten)
04503 {
04504    return exten ? exten->exten : NULL;
04505 }
04506 
04507 char *ast_get_include_name(struct ast_include *inc)
04508 {
04509    return inc ? inc->name : NULL;
04510 }
04511 
04512 char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
04513 {
04514    return ip ? ip->pattern : NULL;
04515 }
04516 
04517 int ast_get_extension_priority(struct ast_exten *exten)
04518 {
04519    return exten ? exten->priority : -1;
04520 }
04521 
04522 /*
04523  * Registrar info functions ...
04524  */
04525 char *ast_get_context_registrar(struct ast_context *c)
04526 {
04527    return c ? c->registrar : NULL;
04528 }
04529 
04530 char *ast_get_extension_registrar(struct ast_exten *e)
04531 {
04532    return e ? e->registrar : NULL;
04533 }
04534 
04535 char *ast_get_include_registrar(struct ast_include *i)
04536 {
04537    return i ? i->registrar : NULL;
04538 }
04539 
04540 char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
04541 {
04542    return ip ? ip->registrar : NULL;
04543 }
04544 
04545 char *ast_get_extension_app(struct ast_exten *e)
04546 {
04547    return e ? e->app : NULL;
04548 }
04549 
04550 void *ast_get_extension_app_data(struct ast_exten *e)
04551 {
04552    return e ? e->data : NULL;
04553 }
04554 
04555 char *ast_get_switch_name(struct ast_sw *sw)
04556 {
04557    return sw ? sw->name : NULL;
04558 }
04559 
04560 char *ast_get_switch_data(struct ast_sw *sw)
04561 {
04562    return sw ? sw->data : NULL;
04563 }
04564 
04565 char *ast_get_switch_registrar(struct ast_sw *sw)
04566 {
04567    return sw ? sw->registrar : NULL;
04568 }
04569 
04570 /*
04571  * Walking functions ...
04572  */
04573 struct ast_context *ast_walk_contexts(struct ast_context *con)
04574 {
04575    if (!con)
04576       return contexts;
04577    else
04578       return con->next;
04579 }
04580 
04581 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
04582    struct ast_exten *exten)
04583 {
04584    if (!exten)
04585       return con ? con->root : NULL;
04586    else
04587       return exten->next;
04588 }
04589 
04590 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
04591    struct ast_sw *sw)
04592 {
04593    if (!sw)
04594       return con ? con->alts : NULL;
04595    else
04596       return sw->next;
04597 }
04598 
04599 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
04600    struct ast_exten *priority)
04601 {
04602    if (!priority)
04603       return exten;
04604    else
04605       return priority->peer;
04606 }
04607 
04608 struct ast_include *ast_walk_context_includes(struct ast_context *con,
04609    struct ast_include *inc)
04610 {
04611    if (!inc)
04612       return con ? con->includes : NULL;
04613    else
04614       return inc->next;
04615 }
04616 
04617 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
04618    struct ast_ignorepat *ip)
04619 {
04620    if (!ip)
04621       return con ? con->ignorepats : NULL;
04622    else
04623       return ip->next;
04624 }

Generated on Fri Oct 31 07:05:08 2003 for Asterisk by doxygen 1.3.4