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

pbx.c

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

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

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

Generated on Sun Apr 18 23:33:54 2004 for Asterisk by doxygen 1.3.6-20040222