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@digium.com>
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 <asterisk/utils.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <setjmp.h>
00036 #include <ctype.h>
00037 #include <errno.h>
00038 #include <time.h>
00039 #include <sys/time.h>
00040 #include "asterisk.h"
00041 
00042 /*
00043  * I M P O R T A N T :
00044  *
00045  *    The speed of extension handling will likely be among the most important
00046  * aspects of this PBX.  The switching scheme as it exists right now isn't
00047  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
00048  * of priorities, but a constant search time here would be great ;-) 
00049  *
00050  */
00051 
00052 #ifdef LOW_MEMORY
00053 #define EXT_DATA_SIZE 256
00054 #else
00055 #define EXT_DATA_SIZE 8192
00056 #endif
00057 
00058 struct ast_context;
00059 
00060 /* ast_exten: An extension */
00061 struct ast_exten {
00062    char exten[AST_MAX_EXTENSION];      /* Extension name */
00063    int matchcid;           /* Match caller id ? */
00064    char cidmatch[AST_MAX_EXTENSION];   /* Caller id to match for this extension */
00065    int priority;           /* Priority */
00066    struct ast_context *parent;      /* An extension */
00067    char app[AST_MAX_EXTENSION];     /* Application to execute */
00068    void *data;          /* Data to use */
00069    void (*datad)(void *);        /* Data destructor */
00070    struct ast_exten *peer;       /* Next higher priority with our extension */
00071    char *registrar;        /* Registrar */
00072    struct ast_exten *next;       /* Extension with a greater ID */
00073 };
00074 
00075 /* ast_include: include= support in extensions.conf */
00076 struct ast_include {
00077    char name[AST_MAX_EXTENSION];    
00078    char rname[AST_MAX_EXTENSION];      /* Context to include */
00079    char *registrar;        /* Registrar */
00080    int hastime;            /* If time construct exists */
00081    unsigned int monthmask;       /* Mask for month */
00082    unsigned int daymask;         /* Mask for date */
00083    unsigned int dowmask;         /* Mask for day of week (mon-sun) */
00084    unsigned int minmask[24];     /* Mask for minute */
00085    struct ast_include *next;     /* Link them together */
00086 };
00087 
00088 /* ast_sw: Switch statement in extensions.conf */
00089 struct ast_sw {
00090    char name[AST_MAX_EXTENSION];
00091    char *registrar;        /* Registrar */
00092    char data[AST_MAX_EXTENSION];    /* Data load */
00093    struct ast_sw *next;       /* Link them together */
00094 };
00095 
00096 struct ast_ignorepat {
00097    char pattern[AST_MAX_EXTENSION];
00098    char *registrar;
00099    struct ast_ignorepat *next;
00100 };
00101 
00102 /* ast_context: An extension context */
00103 struct ast_context {
00104    char name[AST_MAX_EXTENSION];    /* Name of the context */
00105    ast_mutex_t lock;          /* A lock to prevent multiple threads from clobbering the context */
00106    struct ast_exten *root;       /* The root of the list of extensions */
00107    struct ast_context *next;     /* Link them together */
00108    struct ast_include *includes;    /* Include other contexts */
00109    struct ast_ignorepat *ignorepats;   /* Patterns for which to continue playing dialtone */
00110    char *registrar;        /* Registrar */
00111    struct ast_sw *alts;       /* Alternative switches */
00112 };
00113 
00114 
00115 /* ast_app: An application */
00116 struct ast_app {
00117    char name[AST_MAX_APP];       /* Name of the application */
00118    int (*execute)(struct ast_channel *chan, void *data);
00119    char *synopsis;            /* Synopsis text for 'show applications' */
00120    char *description;         /* Description (help text) for 'show application <name>' */
00121    struct ast_app *next;         /* Next app in list */
00122 };
00123 
00124 /* ast_state_cb: An extension state notify */
00125 struct ast_state_cb {
00126     int id;
00127     void *data;
00128     ast_state_cb_type callback;
00129     struct ast_state_cb *next;
00130 };
00131        
00132 struct ast_hint {
00133     struct ast_exten *exten;
00134     int laststate; 
00135     struct ast_state_cb *callbacks;
00136     struct ast_hint *next;
00137 };
00138 
00139 
00140 static int pbx_builtin_prefix(struct ast_channel *, void *);
00141 static int pbx_builtin_suffix(struct ast_channel *, void *);
00142 static int pbx_builtin_stripmsd(struct ast_channel *, void *);
00143 static int pbx_builtin_answer(struct ast_channel *, void *);
00144 static int pbx_builtin_goto(struct ast_channel *, void *);
00145 static int pbx_builtin_hangup(struct ast_channel *, void *);
00146 static int pbx_builtin_background(struct ast_channel *, void *);
00147 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
00148 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
00149 static int pbx_builtin_atimeout(struct ast_channel *, void *);
00150 static int pbx_builtin_wait(struct ast_channel *, void *);
00151 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00152 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
00153 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00154 static int pbx_builtin_setaccount(struct ast_channel *, void *);
00155 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00156 static int pbx_builtin_ringing(struct ast_channel *, void *);
00157 static int pbx_builtin_progress(struct ast_channel *, void *);
00158 static int pbx_builtin_congestion(struct ast_channel *, void *);
00159 static int pbx_builtin_busy(struct ast_channel *, void *);
00160 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
00161 static int pbx_builtin_noop(struct ast_channel *, void *);
00162 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00163 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00164 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00165 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00166 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00167 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00168 int pbx_builtin_setvar(struct ast_channel *, void *);
00169 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
00170 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
00171 
00172 static struct varshead globals;
00173 
00174 static struct pbx_builtin {
00175    char name[AST_MAX_APP];
00176    int (*execute)(struct ast_channel *chan, void *data);
00177    char *synopsis;
00178    char *description;
00179 } builtins[] = 
00180 {
00181    /* These applications are built into the PBX core and do not
00182       need separate modules
00183       
00184        */
00185 
00186    { "AbsoluteTimeout", pbx_builtin_atimeout,
00187    "Set absolute maximum time of call",
00188    "  AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted\n"
00189    "for a call.  A setting of 0 disables the timeout.  Always returns 0.\n" 
00190    },
00191 
00192    { "Answer", pbx_builtin_answer, 
00193    "Answer a channel if ringing", 
00194    "  Answer(): If the channel is ringing, answer it, otherwise do nothing. \n"
00195    "Returns 0 unless it tries to answer the channel and fails.\n"   
00196    },
00197 
00198    { "BackGround", pbx_builtin_background,
00199    "Play a file while awaiting extension",
00200    "  Background(filename[|options[|langoverride]]): Plays a given file, while simultaneously\n"
00201    "waiting for the user to begin typing an extension. The  timeouts do not\n"
00202    "count until the last BackGround application has ended.\n" 
00203    "Options may also be  included following a pipe symbol. The 'skip'\n"
00204    "option causes the playback of the message to  be  skipped  if  the  channel\n"
00205    "is not in the 'up' state (i.e. it hasn't been  answered  yet. If 'skip' is \n"
00206    "specified, the application will return immediately should the channel not be\n"
00207    "off hook.  Otherwise, unless 'noanswer' is specified, the channel channel will\n"
00208    "be answered before the sound is played. Not all channels support playing\n"
00209    "messages while still hook. The 'langoverride' may be a language to use for\n"
00210    "playing the prompt which differs from the current language of the channel\n"
00211    "Returns -1 if the channel was hung up, or if the file does not exist. \n"
00212    "Returns 0 otherwise.\n"
00213    },
00214 
00215    { "Busy", pbx_builtin_busy,
00216    "Indicate busy condition and stop",
00217    "  Busy([timeout]): Requests that the channel indicate busy condition and\n"
00218    "then waits for the user to hang up or the optional timeout to expire.\n"
00219    "Always returns -1." 
00220    },
00221 
00222    { "Congestion", pbx_builtin_congestion,
00223    "Indicate congestion and stop",
00224    "  Congestion([timeout]): Requests that the channel indicate congestion\n"
00225    "and then waits for the user to hang up or for the optional timeout to\n"
00226    "expire.  Always returns -1." 
00227    },
00228 
00229    { "DigitTimeout", pbx_builtin_dtimeout,
00230    "Set maximum timeout between digits",
00231    "  DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
00232    "digits when the user is typing in an extension. When this timeout expires,\n"
00233    "after the user has started to type in an extension, the extension will be\n"
00234    "considered complete, and will be interpreted. Note that if an extension\n"
00235    "typed in is valid, it will not have to timeout to be tested, so typically\n"
00236    "at the expiry of this timeout, the extension will be considered invalid\n"
00237    "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
00238    "exist the call would be terminated). Always returns 0.\n" 
00239    },
00240 
00241    { "Goto", pbx_builtin_goto, 
00242    "Goto a particular priority, extension, or context",
00243    "  Goto([[context|]extension|]priority):  Set the  priority to the specified\n"
00244    "value, optionally setting the extension and optionally the context as well.\n"
00245    "The extension BYEXTENSION is special in that it uses the current extension,\n"
00246    "thus  permitting you to go to a different context, without specifying a\n"
00247    "specific extension. Always returns 0, even if the given context, extension,\n"
00248    "or priority is invalid.\n" 
00249    },
00250 
00251    { "GotoIf", pbx_builtin_gotoif,
00252    "Conditional goto",
00253    "  GotoIf(Condition?label1:label2): Go to label 1 if condition is\n"
00254    "true, to label2 if condition is false. Either label1 or label2 may be\n"
00255    "omitted (in that case, we just don't take the particular branch) but not\n"
00256    "both. Look for the condition syntax in examples or documentation." 
00257    },
00258 
00259    { "GotoIfTime", pbx_builtin_gotoiftime,
00260    "Conditional goto on current time",
00261    "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri):\n"
00262    "If the current time matches the specified time, then branch to the specified\n"
00263    "extension. Each of the elements may be specified either as '*' (for always)\n"
00264    "or as a range. See the 'include' syntax for details." 
00265    },
00266    
00267    { "Hangup", pbx_builtin_hangup,
00268    "Unconditional hangup",
00269    "  Hangup(): Unconditionally hangs up a given channel by returning -1 always.\n" 
00270    },
00271 
00272    { "NoOp", pbx_builtin_noop,
00273    "No operation",
00274    "  NoOp(): No-operation; Does nothing." 
00275    },
00276 
00277    { "Prefix", pbx_builtin_prefix, 
00278    "Prepend leading digits",
00279    "  Prefix(digits): Prepends the digit string specified by digits to the\n"
00280    "channel's associated extension. For example, the number 1212 when prefixed\n"
00281    "with '555' will become 5551212. This app always returns 0, and the PBX will\n"
00282    "continue processing at the next priority for the *new* extension.\n"
00283    "  So, for example, if priority  3  of 1212 is  Prefix  555, the next step\n"
00284    "executed will be priority 4 of 5551212. If you switch into an extension\n"
00285    "which has no first step, the PBX will treat it as though the user dialed an\n"
00286    "invalid extension.\n" 
00287    },
00288 
00289    { "Progress", pbx_builtin_progress,
00290    "Indicate progress",
00291    "  Progress(): Request that the channel indicate in-band progress is \n"
00292    "available to the user.\nAlways returns 0.\n" 
00293    },
00294 
00295    { "ResetCDR", pbx_builtin_resetcdr,
00296    "Resets the Call Data Record",
00297    "  ResetCDR([options]):  Causes the Call Data Record to be reset, optionally\n"
00298    "storing the current CDR before zeroing it out (if 'w' option is specifed).\n"
00299    "record WILL be stored.\nAlways returns 0.\n"  
00300    },
00301 
00302    { "ResponseTimeout", pbx_builtin_rtimeout,
00303    "Set maximum timeout awaiting response",
00304    "  ResponseTimeout(seconds): Set the maximum amount of time permitted after\n"
00305    "falling through a series of priorities for a channel in which the user may\n"
00306    "begin typing an extension. If the user does not type an extension in this\n"
00307    "amount of time, control will pass to the 't' extension if it exists, and\n"
00308    "if not the call would be terminated.\nAlways returns 0.\n"  
00309    },
00310 
00311    { "Ringing", pbx_builtin_ringing,
00312    "Indicate ringing tone",
00313    "  Ringing(): Request that the channel indicate ringing tone to the user.\n"
00314    "Always returns 0.\n" 
00315    },
00316 
00317    { "SayNumber", pbx_builtin_saynumber,
00318    "Say Number",
00319    "  SayNumber(digits[,gender]): Says the passed number. SayNumber is using\n" 
00320    "the current language setting for the channel. (See app SetLanguage).\n"
00321    },
00322 
00323    { "SayDigits", pbx_builtin_saydigits,
00324    "Say Digits",
00325    "  SayDigits(digits): Says the passed digits. SayDigits is using the\n" 
00326    "current language setting for the channel. (See app setLanguage)\n"
00327    },
00328 
00329    { "SayAlpha", pbx_builtin_saycharacters,
00330    "Say Alpha",
00331    "  SayAlpha(string): Spells the passed string\n" 
00332    },
00333 
00334    { "SayPhonetic", pbx_builtin_sayphonetic,
00335    "Say Phonetic",
00336    "  SayPhonetic(string): Spells the passed string with phonetic alphabet\n" 
00337    },
00338 
00339    { "SetAccount", pbx_builtin_setaccount,
00340    "Sets account code",
00341    "  SetAccount([account]):  Set  the  channel account code for billing\n"
00342    "purposes. Always returns 0.\n"  
00343    },
00344 
00345    { "SetAMAFlags", pbx_builtin_setamaflags,
00346    "Sets AMA Flags",
00347    "  SetAMAFlags([flag]):  Set  the  channel AMA Flags for billing\n"
00348    "purposes. Always returns 0.\n"  
00349    },
00350 
00351    { "SetGlobalVar", pbx_builtin_setglobalvar,
00352    "Set global variable to value",
00353    "  SetGlobalVar(#n=value): Sets global variable n to value. Global\n" 
00354    "variable are available across channels.\n"
00355    },
00356 
00357    { "SetLanguage", pbx_builtin_setlanguage,
00358    "Sets user language",
00359    "  SetLanguage(language):  Set  the  channel  language to 'language'.  This\n"
00360    "information is used for the syntax in generation of numbers, and to choose\n"
00361    "a natural language file when available.\n"
00362    "  For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
00363    "requested  to  be  played,  if the file 'fr/demo-congrats' exists, then\n"
00364    "it will play that file, and if not will play the normal 'demo-congrats'.\n"
00365    "Always returns 0.\n"  
00366    },
00367 
00368    { "SetVar", pbx_builtin_setvar,
00369    "Set variable to value",
00370    "  Setvar(#n=value): Sets channel specific variable n to value" 
00371    },
00372 
00373    { "StripMSD", pbx_builtin_stripmsd,
00374    "Strip leading digits",
00375    "  StripMSD(count): Strips the leading 'count' digits from the channel's\n"
00376    "associated extension. For example, the number 5551212 when stripped with a\n"
00377    "count of 3 would be changed to 1212. This app always returns 0, and the PBX\n"
00378    "will continue processing at the next priority for the *new* extension.\n"
00379    "  So, for example, if priority 3 of 5551212 is StripMSD 3, the next step\n"
00380    "executed will be priority 4 of 1212. If you switch into an extension which\n"
00381    "has no first step, the PBX will treat it as though the user dialed an\n"
00382    "invalid extension.\n" 
00383    },
00384 
00385    { "Suffix", pbx_builtin_suffix, 
00386    "Append trailing digits",
00387    "  Suffix(digits): Appends the  digit  string  specified  by  digits to the\n"
00388    "channel's associated extension. For example, the number 555 when  suffixed\n"
00389    "with '1212' will become 5551212. This app always returns 0, and the PBX will\n"
00390    "continue processing at the next priority for the *new* extension.\n"
00391    "  So, for example, if priority  3  of  555 is Suffix 1212, the  next  step\n"
00392    "executed will be priority 4 of 5551212. If  you  switch  into an  extension\n"
00393    "which has no first step, the PBX will treat it as though the user dialed an\n"
00394    "invalid extension.\n" 
00395    },
00396 
00397    { "Wait", pbx_builtin_wait, 
00398    "Waits for some time", 
00399    "  Wait(seconds): Waits for a specified number of seconds, then returns 0.\n"
00400    "seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds)\n" 
00401    },
00402 
00403    { "WaitExten", pbx_builtin_waitexten, 
00404    "Waits for some time", 
00405    "  Wait(seconds): Waits for the user to enter a new extension for the \n"
00406    "specified number of seconds, then returns 0.  Seconds can be passed with\n"
00407    "fractions of a second. (eg: 1.5 = 1.5 seconds)\n" 
00408    },
00409 
00410 };
00411 
00412 AST_MUTEX_DEFINE_STATIC(applock);      /* Lock for the application list */
00413 static struct ast_context *contexts = NULL;
00414 AST_MUTEX_DEFINE_STATIC(conlock);      /* Lock for the ast_context list */
00415 static struct ast_app *apps = NULL;
00416 
00417 AST_MUTEX_DEFINE_STATIC(switchlock);      /* Lock for switches */
00418 struct ast_switch *switches = NULL;
00419 
00420 AST_MUTEX_DEFINE_STATIC(hintlock);     /* Lock for extension state notifys */
00421 static int stateid = 1;
00422 struct ast_hint *hints = NULL;
00423 struct ast_state_cb *statecbs = NULL;
00424 
00425 int pbx_exec(struct ast_channel *c,       /* Channel */
00426       struct ast_app *app,    /* Application */
00427       void *data,       /* Data for execution */
00428       int newstack)        /* Force stack increment */
00429 {
00430    /* This function is special.  It saves the stack so that no matter
00431       how many times it is called, it returns to the same place */
00432    int res;
00433    
00434    char *saved_c_appl;
00435    char *saved_c_data;
00436    
00437    int stack = c->stack;
00438    int (*execute)(struct ast_channel *chan, void *data) = app->execute; 
00439 
00440    if (newstack && stack > AST_CHANNEL_MAX_STACK - 2) {
00441       /* Don't allow us to go over the max number of stacks we
00442          permit saving. */
00443       ast_log(LOG_WARNING, "Stack overflow, cannot create another stack\n");
00444       return -1;
00445    }
00446    if (newstack && (res = setjmp(c->jmp[++c->stack]))) {
00447       /* Okay, here's where it gets weird.  If newstack is non-zero, 
00448          then we increase the stack increment, but setjmp is not going
00449          to return until longjmp is called -- when the application
00450          exec'd is finished running. */
00451       if (res == 1)
00452          res = 0;
00453       if (c->stack != stack + 1) 
00454          ast_log(LOG_WARNING, "Stack returned to an unexpected place!\n");
00455       else if (c->app[c->stack])
00456          ast_log(LOG_WARNING, "Application may have forgotten to free its memory\n");
00457       c->stack = stack;
00458       return res;
00459    } else {
00460       if (c->cdr)
00461          ast_cdr_setapp(c->cdr, app->name, data);
00462 
00463       /* save channel values */
00464       saved_c_appl= c->appl;
00465       saved_c_data= c->data;
00466 
00467       c->appl = app->name;
00468       c->data = data;      
00469       res = execute(c, data);
00470       /* restore channel values */
00471       c->appl= saved_c_appl;
00472       c->data= saved_c_data;
00473 
00474       /* Any application that returns, we longjmp back, just in case. */
00475       if (c->stack != stack + 1)
00476          ast_log(LOG_WARNING, "Stack is not at expected value\n");
00477       longjmp(c->jmp[stack+1], res);
00478       /* Never returns */
00479    }
00480 }
00481 
00482 
00483 /* Go no deeper than this through includes (not counting loops) */
00484 #define AST_PBX_MAX_STACK  64
00485 
00486 #define HELPER_EXISTS 0
00487 #define HELPER_SPAWN 1
00488 #define HELPER_EXEC 2
00489 #define HELPER_CANMATCH 3
00490 #define HELPER_MATCHMORE 4
00491 
00492 struct ast_app *pbx_findapp(char *app) 
00493 {
00494    struct ast_app *tmp;
00495 
00496    if (ast_mutex_lock(&applock)) {
00497       ast_log(LOG_WARNING, "Unable to obtain application lock\n");
00498       return NULL;
00499    }
00500    tmp = apps;
00501    while(tmp) {
00502       if (!strcasecmp(tmp->name, app))
00503          break;
00504       tmp = tmp->next;
00505    }
00506    ast_mutex_unlock(&applock);
00507    return tmp;
00508 }
00509 
00510 static struct ast_switch *pbx_findswitch(char *sw)
00511 {
00512    struct ast_switch *asw;
00513 
00514    if (ast_mutex_lock(&switchlock)) {
00515       ast_log(LOG_WARNING, "Unable to obtain application lock\n");
00516       return NULL;
00517    }
00518    asw = switches;
00519    while(asw) {
00520       if (!strcasecmp(asw->name, sw))
00521          break;
00522       asw = asw->next;
00523    }
00524    ast_mutex_unlock(&switchlock);
00525    return asw;
00526 }
00527 
00528 static inline int include_valid(struct ast_include *i)
00529 {
00530    struct tm tm;
00531    time_t t;
00532 
00533    if (!i->hastime)
00534       return 1;
00535    time(&t);
00536    localtime_r(&t,&tm);
00537 
00538    /* If it's not the right month, return */
00539    if (!(i->monthmask & (1 << tm.tm_mon))) {
00540       return 0;
00541    }
00542 
00543    /* If it's not that time of the month.... */
00544    /* Warning, tm_mday has range 1..31! */
00545    if (!(i->daymask & (1 << (tm.tm_mday-1))))
00546       return 0;
00547 
00548    /* If it's not the right day of the week */
00549    if (!(i->dowmask & (1 << tm.tm_wday)))
00550       return 0;
00551 
00552    /* Sanity check the hour just to be safe */
00553    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
00554       ast_log(LOG_WARNING, "Insane time...\n");
00555       return 0;
00556    }
00557 
00558    /* Now the tough part, we calculate if it fits
00559       in the right time based on min/hour */
00560    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
00561       return 0;
00562 
00563    /* If we got this far, then we're good */
00564    return 1;
00565 }
00566 
00567 static void pbx_destroy(struct ast_pbx *p)
00568 {
00569    free(p);
00570 }
00571 
00572 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
00573    /* All patterns begin with _ */\
00574    if (pattern[0] != '_') \
00575       return 0;\
00576    /* Start optimistic */\
00577    match=1;\
00578    pattern++;\
00579    while(match && *data && *pattern && (*pattern != '/')) {\
00580       switch(toupper(*pattern)) {\
00581       case '[': \
00582       {\
00583          int i,border=0;\
00584          char *where;\
00585          match=0;\
00586          pattern++;\
00587          where=strchr(pattern,']');\
00588          if (where)\
00589             border=(int)(where-pattern);\
00590          if (!where || border > strlen(pattern)) {\
00591             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
00592             return match;\
00593          }\
00594          for (i=0; i<border; i++) {\
00595             int res=0;\
00596             if (i+2<border)\
00597                if (pattern[i+1]=='-') {\
00598                   if (*data >= pattern[i] && *data <= pattern[i+2]) {\
00599                      res=1;\
00600                   } else {\
00601                      i+=2;\
00602                      continue;\
00603                   }\
00604                }\
00605             if (res==1 || *data==pattern[i]) {\
00606                match = 1;\
00607                break;\
00608             }\
00609          }\
00610          pattern+=border;\
00611          break;\
00612       }\
00613       case 'N':\
00614          if ((*data < '2') || (*data > '9'))\
00615             match=0;\
00616          break;\
00617       case 'X':\
00618          if ((*data < '0') || (*data > '9'))\
00619             match = 0;\
00620          break;\
00621       case 'Z':\
00622          if ((*data < '1') || (*data > '9'))\
00623             match = 0;\
00624          break;\
00625       case '.':\
00626          /* Must match */\
00627          return 1;\
00628       case ' ':\
00629       case '-':\
00630          /* Ignore these characters */\
00631          data--;\
00632          break;\
00633       default:\
00634          if (*data != *pattern)\
00635             match =0;\
00636       }\
00637       data++;\
00638       pattern++;\
00639    }\
00640 }
00641 
00642 int ast_extension_match(char *pattern, char *data)
00643 {
00644    int match;
00645    /* If they're the same return */
00646    if (!strcmp(pattern, data))
00647       return 1;
00648    EXTENSION_MATCH_CORE(data,pattern,match);
00649    /* Must be at the end of both */
00650    if (*data || (*pattern && (*pattern != '/')))
00651       match = 0;
00652    return match;
00653 }
00654 
00655 static int extension_close(char *pattern, char *data, int needmore)
00656 {
00657    int match;
00658    /* If "data" is longer, it can'be a subset of pattern unless
00659       pattern is a pattern match */
00660    if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
00661       return 0;
00662    
00663    if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) && 
00664       (!needmore || (strlen(pattern) > strlen(data)))) {
00665       return 1;
00666    }
00667    EXTENSION_MATCH_CORE(data,pattern,match);
00668    /* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
00669    if (!needmore || *pattern) {
00670       return match;
00671    } else
00672       return 0;
00673 }
00674 
00675 struct ast_context *ast_context_find(char *name)
00676 {
00677    struct ast_context *tmp;
00678    ast_mutex_lock(&conlock);
00679    if (name) {
00680       tmp = contexts;
00681       while(tmp) {
00682          if (!strcasecmp(name, tmp->name))
00683             break;
00684          tmp = tmp->next;
00685       }
00686    } else
00687       tmp = contexts;
00688    ast_mutex_unlock(&conlock);
00689    return tmp;
00690 }
00691 
00692 #define STATUS_NO_CONTEXT   1
00693 #define STATUS_NO_EXTENSION 2
00694 #define STATUS_NO_PRIORITY  3
00695 #define STATUS_SUCCESS      4
00696 
00697 static int matchcid(char *cidpattern, char *callerid)
00698 {
00699    char tmp[AST_MAX_EXTENSION];
00700    int failresult;
00701    char *name, *num;
00702    
00703    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
00704       failing to get a number should count as a match, otherwise not */
00705 
00706 
00707    if (!ast_strlen_zero(cidpattern))
00708       failresult = 0;
00709    else
00710       failresult = 1;
00711 
00712    if (!callerid)
00713       return failresult;
00714 
00715    /* Copy original Caller*ID */
00716    strncpy(tmp, callerid, sizeof(tmp)-1);
00717    /* Parse Number */
00718    if (ast_callerid_parse(tmp, &name, &num)) 
00719       return failresult;
00720    if (!num)
00721       return failresult;
00722    ast_shrink_phone_number(num);
00723    return ast_extension_match(cidpattern, num);
00724 }
00725 
00726 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)
00727 {
00728    int x, res;
00729    struct ast_context *tmp;
00730    struct ast_exten *e, *eroot;
00731    struct ast_include *i;
00732    struct ast_sw *sw;
00733    struct ast_switch *asw;
00734 
00735    /* Initialize status if appropriate */
00736    if (!*stacklen) {
00737       *status = STATUS_NO_CONTEXT;
00738       *swo = NULL;
00739       *data = NULL;
00740    }
00741    /* Check for stack overflow */
00742    if (*stacklen >= AST_PBX_MAX_STACK) {
00743       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
00744       return NULL;
00745    }
00746    /* Check first to see if we've already been checked */
00747    for (x=0;x<*stacklen;x++) {
00748       if (!strcasecmp(incstack[x], context))
00749          return NULL;
00750    }
00751    tmp = contexts;
00752    while(tmp) {
00753       /* Match context */
00754       if (!strcmp(tmp->name, context)) {
00755          if (*status < STATUS_NO_EXTENSION)
00756             *status = STATUS_NO_EXTENSION;
00757          eroot = tmp->root;
00758          while(eroot) {
00759             /* Match extension */
00760             if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
00761                   ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten, 0))) ||
00762                   ((action == HELPER_MATCHMORE) && (extension_close(eroot->exten, exten, 1)))) &&
00763                   (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
00764                   e = eroot;
00765                   if (*status < STATUS_NO_PRIORITY)
00766                      *status = STATUS_NO_PRIORITY;
00767                   while(e) {
00768                      /* Match priority */
00769                      if (e->priority == priority) {
00770                         *status = STATUS_SUCCESS;
00771                         return e;
00772                      }
00773                      e = e->peer;
00774                   }
00775             }
00776             eroot = eroot->next;
00777          }
00778          /* Check alternative switches */
00779          sw = tmp->alts;
00780          while(sw) {
00781             if ((asw = pbx_findswitch(sw->name))) {
00782                if (action == HELPER_CANMATCH)
00783                   res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->data) : 0;
00784                else if (action == HELPER_MATCHMORE)
00785                   res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->data) : 0;
00786                else
00787                   res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->data) : 0;
00788                if (res) {
00789                   /* Got a match */
00790                   *swo = asw;
00791                   *data = sw->data;
00792                   return NULL;
00793                }
00794             } else {
00795                ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
00796             }
00797             sw = sw->next;
00798          }
00799          /* Setup the stack */
00800          incstack[*stacklen] = tmp->name;
00801          (*stacklen)++;
00802          /* Now try any includes we have in this context */
00803          i = tmp->includes;
00804          while(i) {
00805             if (include_valid(i)) {
00806                if ((e = pbx_find_extension(chan, i->rname, exten, priority, callerid, action, incstack, stacklen, status, swo, data))) 
00807                   return e;
00808                if (*swo) 
00809                   return NULL;
00810             }
00811             i = i->next;
00812          }
00813       }
00814       tmp = tmp->next;
00815    }
00816    return NULL;
00817 }
00818 
00819 static void pbx_substitute_variables_temp(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen)
00820 {
00821    char *first,*second;
00822    char tmpvar[80] = "";
00823    time_t thistime;
00824    struct tm brokentime;
00825    int offset,offset2;
00826    struct ast_var_t *variables;
00827    char *name, *num; /* for callerid name + num variables */
00828    struct varshead *headp=NULL;
00829 
00830    if (c) 
00831       headp=&c->varshead;
00832    *ret=NULL;
00833    /* Now we have the variable name on cp3 */
00834    if (!strncasecmp(var,"LEN(",4)) {
00835       int len=strlen(var);
00836       int len_len=4;
00837       if (strrchr(var,')')) {
00838          char cp3[80];
00839          strncpy(cp3, var, sizeof(cp3) - 1);
00840          cp3[len-len_len-1]='\0';
00841          sprintf(workspace,"%d",(int)strlen(cp3));
00842          *ret = workspace;
00843       } else {
00844          /* length is zero */
00845          *ret = "0";
00846       }
00847    } else if ((first=strchr(var,':'))) {
00848       strncpy(tmpvar, var, sizeof(tmpvar) - 1);
00849       first = strchr(tmpvar, ':');
00850       if (!first)
00851          first = tmpvar + strlen(tmpvar);
00852       *first='\0';
00853       pbx_substitute_variables_temp(c,tmpvar,ret,workspace,workspacelen - 1);
00854       if (!(*ret)) return;
00855       offset=atoi(first+1);
00856       if ((second=strchr(first+1,':'))) {
00857          *second='\0';
00858          offset2=atoi(second+1);
00859       } else
00860          offset2=strlen(*ret)-offset;
00861       if (abs(offset)>strlen(*ret)) {
00862          if (offset>=0) 
00863             offset=strlen(*ret);
00864          else 
00865             offset=-strlen(*ret);
00866       }
00867       if ((offset<0 && offset2>-offset) || (offset>=0 && offset+offset2>strlen(*ret))) {
00868          if (offset>=0) 
00869             offset2=strlen(*ret)-offset;
00870          else 
00871             offset2=strlen(*ret)+offset;
00872       }
00873       if (offset>=0)
00874          *ret+=offset;
00875       else
00876          *ret+=strlen(*ret)+offset;
00877       (*ret)[offset2] = '\0';
00878    } else if (c && !strcmp(var, "CALLERIDNUM")) {
00879       if (c->callerid)
00880          strncpy(workspace, c->callerid, workspacelen - 1);
00881       ast_callerid_parse(workspace, &name, &num);
00882       if (num) {
00883          ast_shrink_phone_number(num);
00884          *ret = num;
00885       } else
00886          *ret = workspace;
00887    } else if (c && !strcmp(var, "CALLERIDNAME")) {
00888       if (c->callerid)
00889          strncpy(workspace, c->callerid, workspacelen - 1);
00890       ast_callerid_parse(workspace, &name, &num);
00891       if (name)
00892          *ret = name;
00893       else
00894          *ret = workspace;
00895    } else if (c && !strcmp(var, "CALLERID")) {
00896       if (c->callerid) {
00897          strncpy(workspace, c->callerid, workspacelen - 1);
00898          *ret = workspace;
00899       } else 
00900          *ret = NULL;
00901    } else if (c && !strcmp(var, "DNID")) {
00902       if (c->dnid) {
00903          strncpy(workspace, c->dnid, workspacelen - 1);
00904          *ret = workspace;
00905       } else
00906          *ret = NULL;
00907    } else if (c && !strcmp(var, "HINT")) {
00908       if (!ast_get_hint(workspace, workspacelen, c, c->context, c->exten))
00909          *ret = NULL;
00910       else
00911          *ret = workspace;
00912    } else if (c && !strcmp(var, "EXTEN")) {
00913       strncpy(workspace, c->exten, workspacelen - 1);
00914       *ret = workspace;
00915    } else if (c && !strncmp(var, "EXTEN-", strlen("EXTEN-")) && 
00916       /* XXX Remove me eventually */
00917       (sscanf(var + strlen("EXTEN-"), "%d", &offset) == 1)) {
00918       if (offset < 0)
00919          offset=0;
00920       if (offset > strlen(c->exten))
00921          offset = strlen(c->exten);
00922       strncpy(workspace, c->exten + offset, workspacelen - 1);
00923       *ret = workspace;
00924       ast_log(LOG_WARNING, "The use of 'EXTEN-foo' has been deprecated in favor of 'EXTEN:foo'\n");
00925    } else if (c && !strcmp(var, "RDNIS")) {
00926       if (c->rdnis) {
00927          strncpy(workspace, c->rdnis, workspacelen - 1);
00928          *ret = workspace;
00929       } else
00930          *ret = NULL;
00931    } else if (c && !strcmp(var, "CONTEXT")) {
00932       strncpy(workspace, c->context, workspacelen - 1);
00933       *ret = workspace;
00934    } else if (c && !strcmp(var, "PRIORITY")) {
00935       snprintf(workspace, workspacelen, "%d", c->priority);
00936       *ret = workspace;
00937    } else if (c && !strcmp(var, "CALLINGPRES")) {
00938       snprintf(workspace, workspacelen, "%d", c->callingpres);
00939       *ret = workspace;
00940    } else if (c && !strcmp(var, "CHANNEL")) {
00941       strncpy(workspace, c->name, workspacelen - 1);
00942       *ret = workspace;
00943    } else if (c && !strcmp(var, "EPOCH")) {
00944       snprintf(workspace, workspacelen, "%u",(int)time(NULL));
00945       *ret = workspace;
00946    } else if (c && !strcmp(var, "DATETIME")) {
00947       thistime=time(NULL);
00948       localtime_r(&thistime, &brokentime);
00949       snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
00950          brokentime.tm_mday,
00951          brokentime.tm_mon+1,
00952          brokentime.tm_year+1900,
00953          brokentime.tm_hour,
00954          brokentime.tm_min,
00955          brokentime.tm_sec
00956       );
00957       *ret = workspace;
00958    } else if (c && !strcmp(var, "TIMESTAMP")) {
00959       thistime=time(NULL);
00960       localtime_r(&thistime, &brokentime);
00961       /* 20031130-150612 */
00962       snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
00963          brokentime.tm_year+1900,
00964          brokentime.tm_mon+1,
00965          brokentime.tm_mday,
00966          brokentime.tm_hour,
00967          brokentime.tm_min,
00968          brokentime.tm_sec
00969       );
00970       *ret = workspace;
00971    } else if (c && !strcmp(var, "UNIQUEID")) {
00972       snprintf(workspace, workspacelen, "%s", c->uniqueid);
00973       *ret = workspace;
00974    } else if (c && !strcmp(var, "HANGUPCAUSE")) {
00975       snprintf(workspace, workspacelen, "%i", c->hangupcause);
00976       *ret = workspace;
00977    } else if (c && !strcmp(var, "ACCOUNTCODE")) {
00978       strncpy(workspace, c->accountcode, workspacelen - 1);
00979       *ret = workspace;
00980    } else if (c && !strcmp(var, "LANGUAGE")) {
00981       strncpy(workspace, c->language, workspacelen - 1);
00982       *ret = workspace;
00983    } else {
00984       if (c) {
00985          AST_LIST_TRAVERSE(headp,variables,entries) {
00986 #if 0
00987             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
00988 #endif
00989             if (strcasecmp(ast_var_name(variables),var)==0) {
00990                *ret=ast_var_value(variables);
00991                if (*ret) {
00992                   strncpy(workspace, *ret, workspacelen - 1);
00993                   *ret = workspace;
00994                }
00995                break;
00996             }
00997          }
00998       }
00999       if (!(*ret)) {
01000          /* Try globals */
01001          AST_LIST_TRAVERSE(&globals,variables,entries) {
01002 #if 0
01003             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
01004 #endif
01005             if (strcasecmp(ast_var_name(variables),var)==0) {
01006                *ret=ast_var_value(variables);
01007                if (*ret) {
01008                   strncpy(workspace, *ret, workspacelen - 1);
01009                   *ret = workspace;
01010                }
01011             }
01012          }
01013       }
01014       if (!(*ret)) {
01015          int len=strlen(var);
01016          int len_env=strlen("ENV(");
01017          if (len > (len_env+1) && !strncasecmp(var,"ENV(",len_env) && !strcmp(var+len-1,")")) {
01018             char cp3[80] = "";
01019             strncpy(cp3, var, sizeof(cp3) - 1);
01020             cp3[len-1]='\0';
01021             *ret=getenv(cp3+len_env);
01022             if (*ret) {
01023                strncpy(workspace, *ret, workspacelen - 1);
01024                *ret = workspace;
01025             }
01026          }
01027       }
01028    }
01029 }
01030 
01031 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
01032 {
01033    char *cp4;
01034    const char *tmp, *whereweare;
01035    int length;
01036    char workspace[4096];
01037    char ltmp[4096], var[4096];
01038    char *nextvar, *nextexp;
01039    char *vars, *vare;
01040    int pos, brackets, needsub, len;
01041    
01042    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
01043       zero-filled */
01044    whereweare=tmp=cp1;
01045    while(!ast_strlen_zero(whereweare) && count) {
01046       /* Assume we're copying the whole remaining string */
01047       pos = strlen(whereweare);
01048 
01049       /* Look for a variable */
01050       nextvar = strstr(whereweare, "${");
01051       
01052       /* Look for an expression */
01053       nextexp = strstr(whereweare, "$[");
01054       
01055       /* Pick the first one only */
01056       if (nextvar && nextexp) {
01057          if (nextvar < nextexp)
01058             nextexp = NULL;
01059          else
01060             nextvar = NULL;
01061       }
01062       
01063       /* If there is one, we only go that far */
01064       if (nextvar)
01065          pos = nextvar - whereweare;
01066       else if (nextexp)
01067          pos = nextexp - whereweare;
01068       
01069       /* Can't copy more than 'count' bytes */
01070       if (pos > count)
01071          pos = count;
01072       
01073       /* Copy that many bytes */
01074       memcpy(cp2, whereweare, pos);
01075       
01076       count -= pos;
01077       cp2 += pos;
01078       whereweare += pos;
01079       
01080       if (nextvar) {
01081          /* We have a variable.  Find the start and end, and determine
01082             if we are going to have to recursively call ourselves on the
01083             contents */
01084          vars = vare = nextvar + 2;
01085          brackets = 1;
01086          needsub = 0;
01087          
01088          /* Find the end of it */
01089          while(brackets && *vare) {
01090             if ((vare[0] == '$') && (vare[1] == '{')) {
01091                needsub++;
01092                brackets++;
01093             } else if (vare[0] == '}') {
01094                brackets--;
01095             } else if ((vare[0] == '$') && (vare[1] == '['))
01096                needsub++;
01097             vare++;
01098          }
01099          if (brackets)
01100             ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
01101          len = vare - vars - 1;
01102          
01103          /* Skip totally over variable name */
01104          whereweare += ( len + 3);
01105          
01106          /* Store variable name (and truncate) */
01107          memset(var, 0, sizeof(var));
01108          strncpy(var, vars, sizeof(var) - 1);
01109          var[len] = '\0';
01110          
01111          /* Substitute if necessary */
01112          if (needsub) {
01113             memset(ltmp, 0, sizeof(ltmp));
01114             pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
01115             vars = ltmp;
01116          } else {
01117             vars = var;
01118          }
01119          
01120          /* Retrieve variable value */
01121          workspace[0] = '\0';
01122          pbx_substitute_variables_temp(c,vars,&cp4, workspace, sizeof(workspace));
01123          if (cp4) {
01124             length = strlen(cp4);
01125             if (length > count)
01126                length = count;
01127             memcpy(cp2, cp4, length);
01128             count -= length;
01129             cp2 += length;
01130          }
01131          
01132       } else if (nextexp) {
01133          /* We have an expression.  Find the start and end, and determine
01134             if we are going to have to recursively call ourselves on the
01135             contents */
01136          vars = vare = nextexp + 2;
01137          brackets = 1;
01138          needsub = 0;
01139          
01140          /* Find the end of it */
01141          while(brackets && *vare) {
01142             if ((vare[0] == '$') && (vare[1] == '[')) {
01143                needsub++;
01144                brackets++;
01145                vare++;
01146             } else if (vare[0] == '[') {
01147                brackets++;
01148             } else if (vare[0] == ']') {
01149                brackets--;
01150             } else if ((vare[0] == '$') && (vare[1] == '{')) {
01151                needsub++;
01152                vare++;
01153             }
01154             vare++;
01155          }
01156          if (brackets)
01157             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
01158          len = vare - vars - 1;
01159          
01160          /* Skip totally over variable name */
01161          whereweare += ( len + 3);
01162          
01163          /* Store variable name (and truncate) */
01164          memset(var, 0, sizeof(var));
01165          strncpy(var, vars, sizeof(var) - 1);
01166          var[len] = '\0';
01167          
01168          /* Substitute if necessary */
01169          if (needsub) {
01170             memset(ltmp, 0, sizeof(ltmp));
01171             pbx_substitute_variables_helper(c, var, ltmp, sizeof(ltmp) - 1);
01172             vars = ltmp;
01173          } else {
01174             vars = var;
01175          }
01176 
01177          /* Evaluate expression */        
01178          cp4 = ast_expr(vars);
01179          
01180          ast_log(LOG_DEBUG, "Expression is '%s'\n", cp4);
01181          
01182          if (cp4) {
01183             length = strlen(cp4);
01184             if (length > count)
01185                length = count;
01186             memcpy(cp2, cp4, length);
01187             count -= length;
01188             cp2 += length;
01189             free(cp4);
01190          }
01191          
01192       } else
01193          break;
01194    }
01195 }
01196 
01197 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e) {
01198         
01199    memset(passdata, 0, datalen);
01200       
01201    /* No variables or expressions in e->data, so why scan it? */
01202    if (!strstr(e->data,"${") && !strstr(e->data,"$[")) {
01203       strncpy(passdata, e->data, datalen - 1);
01204       passdata[datalen-1] = '\0';
01205       return;
01206    }
01207    
01208    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
01209 }                                                     
01210 
01211 static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, char *callerid, int action) 
01212 {
01213    struct ast_exten *e;
01214    struct ast_app *app;
01215    struct ast_switch *sw;
01216    char *data;
01217    int newstack = 0;
01218    int res;
01219    int status = 0;
01220    char *incstack[AST_PBX_MAX_STACK];
01221    char passdata[EXT_DATA_SIZE];
01222    int stacklen = 0;
01223    char tmp[80];
01224    char tmp2[80];
01225    char tmp3[EXT_DATA_SIZE];
01226 
01227    if (ast_mutex_lock(&conlock)) {
01228       ast_log(LOG_WARNING, "Unable to obtain lock\n");
01229       if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
01230          return 0;
01231       else
01232          return -1;
01233    }
01234    e = pbx_find_extension(c, context, exten, priority, callerid, action, incstack, &stacklen, &status, &sw, &data);
01235    if (e) {
01236       switch(action) {
01237       case HELPER_CANMATCH:
01238          ast_mutex_unlock(&conlock);
01239          return -1;
01240       case HELPER_EXISTS:
01241          ast_mutex_unlock(&conlock);
01242          return -1;
01243       case HELPER_MATCHMORE:
01244          ast_mutex_unlock(&conlock);
01245          return -1;
01246       case HELPER_SPAWN:
01247          newstack++;
01248          /* Fall through */
01249       case HELPER_EXEC:
01250          app = pbx_findapp(e->app);
01251          ast_mutex_unlock(&conlock);
01252          if (app) {
01253             if (c->context != context)
01254                strncpy(c->context, context, sizeof(c->context)-1);
01255             if (c->exten != exten)
01256                strncpy(c->exten, exten, sizeof(c->exten)-1);
01257             c->priority = priority;
01258             pbx_substitute_variables(passdata, sizeof(passdata), c, e);
01259             if (option_debug)
01260                   ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
01261             else if (option_verbose > 2)
01262                   ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", 
01263                         term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
01264                         term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
01265                         term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
01266                         (newstack ? "in new stack" : "in same stack"));
01267             manager_event(EVENT_FLAG_CALL, "Newexten", 
01268                "Channel: %s\r\n"
01269                "Context: %s\r\n"
01270                "Extension: %s\r\n"
01271                "Priority: %d\r\n"
01272                "Application: %s\r\n"
01273                "AppData: %s\r\n"
01274                "Uniqueid: %s\r\n",
01275                c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
01276             res = pbx_exec(c, app, passdata, newstack);
01277             return res;
01278          } else {
01279             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
01280             return -1;
01281          }
01282       default:
01283          ast_log(LOG_WARNING, "Huh (%d)?\n", action);       return -1;
01284       }
01285    } else if (sw) {
01286       switch(action) {
01287       case HELPER_CANMATCH:
01288          ast_mutex_unlock(&conlock);
01289          return -1;
01290       case HELPER_EXISTS:
01291          ast_mutex_unlock(&conlock);
01292          return -1;
01293       case HELPER_MATCHMORE:
01294          ast_mutex_unlock(&conlock);
01295          return -1;
01296       case HELPER_SPAWN:
01297          newstack++;
01298          /* Fall through */
01299       case HELPER_EXEC:
01300          ast_mutex_unlock(&conlock);
01301          if (sw->exec)
01302             res = sw->exec(c, context, exten, priority, callerid, newstack, data);
01303          else {
01304             ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
01305             res = -1;
01306          }
01307          return res;
01308       default:
01309          ast_log(LOG_WARNING, "Huh (%d)?\n", action);
01310          return -1;
01311       }
01312    } else {
01313       ast_mutex_unlock(&conlock);
01314       switch(status) {
01315       case STATUS_NO_CONTEXT:
01316          if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
01317             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
01318          break;
01319       case STATUS_NO_EXTENSION:
01320          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01321             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
01322          break;
01323       case STATUS_NO_PRIORITY:
01324          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01325             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
01326          break;
01327       default:
01328          ast_log(LOG_DEBUG, "Shouldn't happen!\n");
01329       }
01330       
01331       if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
01332          return -1;
01333       else
01334          return 0;
01335    }
01336 
01337 }
01338 
01339 static struct ast_exten *ast_hint_extension(struct ast_channel *c, char *context, char *exten)
01340 {
01341    struct ast_exten *e;
01342    struct ast_switch *sw;
01343    char *data;
01344    int status = 0;
01345    char *incstack[AST_PBX_MAX_STACK];
01346    int stacklen = 0;
01347 
01348    if (ast_mutex_lock(&conlock)) {
01349       ast_log(LOG_WARNING, "Unable to obtain lock\n");
01350       return NULL;
01351    }
01352    e = pbx_find_extension(c, context, exten, PRIORITY_HINT, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data);
01353    ast_mutex_unlock(&conlock);   
01354    return e;
01355 }
01356 
01357 static int ast_extension_state2(struct ast_exten *e)
01358 {
01359    char hint[AST_MAX_EXTENSION] = "";    
01360    char *cur, *rest;
01361    int res = -1;
01362    int allunavailable = 1, allbusy = 1, allfree = 1;
01363    int busy = 0;
01364 
01365    strncpy(hint, ast_get_extension_app(e), sizeof(hint)-1);
01366     
01367    cur = hint;    
01368    do {
01369       rest = strchr(cur, '&');
01370       if (rest) {
01371             *rest = 0;
01372          rest++;
01373       }
01374    
01375       res = ast_device_state(cur);
01376       switch (res) {
01377          case AST_DEVICE_NOT_INUSE:
01378          allunavailable = 0;
01379          allbusy = 0;
01380          break;
01381          case AST_DEVICE_INUSE:
01382          return AST_EXTENSION_INUSE;
01383          case AST_DEVICE_BUSY:
01384          allunavailable = 0;
01385          allfree = 0;
01386          busy = 1;
01387          break;
01388          case AST_DEVICE_UNAVAILABLE:
01389          case AST_DEVICE_INVALID:
01390          allbusy = 0;
01391          allfree = 0;
01392          break;
01393          default:
01394          allunavailable = 0;
01395          allbusy = 0;
01396          allfree = 0;
01397       }
01398             cur = rest;
01399    } while (cur);
01400 
01401    if (allfree)
01402       return AST_EXTENSION_NOT_INUSE;
01403    if (allbusy)
01404       return AST_EXTENSION_BUSY;
01405    if (allunavailable)
01406       return AST_EXTENSION_UNAVAILABLE;
01407    if (busy) 
01408       return AST_EXTENSION_INUSE;
01409    
01410    return AST_EXTENSION_NOT_INUSE;
01411 }
01412 
01413 
01414 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
01415 {
01416    struct ast_exten *e;
01417 
01418    e = ast_hint_extension(c, context, exten);    
01419    if (!e) 
01420       return -1;
01421 
01422    return ast_extension_state2(e);    
01423 }
01424 
01425 int ast_device_state_changed(const char *fmt, ...) 
01426 {
01427    struct ast_hint *list;
01428    struct ast_state_cb *cblist;
01429    char hint[AST_MAX_EXTENSION] = "";
01430    char device[AST_MAX_EXTENSION];
01431    char *cur, *rest;
01432    int state;
01433 
01434    va_list ap;
01435 
01436    va_start(ap, fmt);
01437    vsnprintf(device, sizeof(device), fmt, ap);
01438    va_end(ap);
01439 
01440    rest = strchr(device, '-');
01441    if (rest) {
01442       *rest = 0;
01443    }
01444 
01445    ast_mutex_lock(&hintlock);
01446 
01447    list = hints;
01448 
01449    while (list) {
01450 
01451       strncpy(hint, ast_get_extension_app(list->exten), sizeof(hint) - 1);
01452       cur = hint;
01453       do {
01454          rest = strchr(cur, '&');
01455          if (rest) {
01456             *rest = 0;
01457             rest++;
01458          }
01459          
01460          if (!strcmp(cur, device)) {
01461             /* Found extension execute callbacks  */
01462             state = ast_extension_state2(list->exten);
01463             if ((state != -1) && (state != list->laststate)) {
01464                /* For general callbacks */
01465                cblist = statecbs;
01466                while (cblist) {
01467                   cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
01468                   cblist = cblist->next;
01469                }
01470 
01471                /* For extension callbacks */
01472                cblist = list->callbacks;
01473                while (cblist) {
01474                   cblist->callback(list->exten->parent->name, list->exten->exten, state, cblist->data);
01475                   cblist = cblist->next;
01476                }
01477          
01478                list->laststate = state;
01479             }
01480             break;
01481          }
01482          cur = rest;
01483       } while (cur);
01484       list = list->next;
01485    }
01486    ast_mutex_unlock(&hintlock);
01487    return 1;
01488 }
01489          
01490 int ast_extension_state_add(char *context, char *exten, 
01491              ast_state_cb_type callback, void *data)
01492 {
01493    struct ast_hint *list;
01494    struct ast_state_cb *cblist;
01495    struct ast_exten *e;
01496 
01497    /* No context and extension add callback to statecbs list */
01498    if (!context && !exten) {
01499       ast_mutex_lock(&hintlock);
01500 
01501       cblist = statecbs;
01502       while (cblist) {
01503          if (cblist->callback == callback) {
01504             cblist->data = data;
01505             ast_mutex_unlock(&hintlock);
01506          }
01507          cblist = cblist->next;
01508       }
01509    
01510       /* Now inserts the callback */
01511       cblist = malloc(sizeof(struct ast_state_cb));
01512       if (!cblist) {
01513          ast_mutex_unlock(&hintlock);
01514          return -1;
01515       }
01516       memset(cblist, 0, sizeof(struct ast_state_cb));
01517       cblist->id = 0;
01518       cblist->callback = callback;
01519       cblist->data = data;
01520    
01521             cblist->next = statecbs;
01522       statecbs = cblist;
01523 
01524       ast_mutex_unlock(&hintlock);
01525       return 0;
01526       }
01527 
01528    if (!context || !exten)
01529       return -1;
01530 
01531    /* This callback type is for only one hint */
01532    e = ast_hint_extension(NULL, context, exten);    
01533    if (!e) {
01534       return -1;
01535    }
01536     
01537    ast_mutex_lock(&hintlock);
01538    list = hints;        
01539     
01540    while (list) {
01541       if (list->exten == e)
01542          break;       
01543       list = list->next;    
01544    }
01545 
01546    if (!list) {
01547       ast_mutex_unlock(&hintlock);
01548       return -1;
01549    }
01550 
01551    /* Now inserts the callback */
01552    cblist = malloc(sizeof(struct ast_state_cb));
01553    if (!cblist) {
01554       ast_mutex_unlock(&hintlock);
01555       return -1;
01556    }
01557    memset(cblist, 0, sizeof(struct ast_state_cb));
01558    cblist->id = stateid++;
01559    cblist->callback = callback;
01560    cblist->data = data;
01561 
01562    cblist->next = list->callbacks;
01563    list->callbacks = cblist;
01564 
01565    ast_mutex_unlock(&hintlock);
01566    return cblist->id;
01567 }
01568 
01569 int ast_extension_state_del(int id, ast_state_cb_type callback)
01570 {
01571    struct ast_hint *list;
01572    struct ast_state_cb *cblist, *cbprev;
01573     
01574    if (!id && !callback)
01575       return -1;
01576             
01577    ast_mutex_lock(&hintlock);
01578 
01579    /* id is zero is a callback without extension */
01580    if (!id) {
01581       cbprev = NULL;
01582       cblist = statecbs;
01583       while (cblist) {
01584          if (cblist->callback == callback) {
01585             if (!cbprev)
01586                   statecbs = cblist->next;
01587             else
01588                   cbprev->next = cblist->next;
01589 
01590             free(cblist);
01591 
01592                ast_mutex_unlock(&hintlock);
01593             return 0;
01594             }
01595             cbprev = cblist;
01596             cblist = cblist->next;
01597       }
01598 
01599          ast_mutex_lock(&hintlock);
01600       return -1;
01601    }
01602 
01603    /* id greater than zero is a callback with extension */
01604    list = hints;
01605    while (list) {
01606       cblist = list->callbacks;
01607       cbprev = NULL;
01608       while (cblist) {
01609             if (cblist->id==id) {
01610             if (!cbprev)
01611                   list->callbacks = cblist->next;     
01612             else
01613                   cbprev->next = cblist->next;
01614       
01615             free(cblist);
01616       
01617             ast_mutex_unlock(&hintlock);
01618             return 0;      
01619             }     
01620                cbprev = cblist;           
01621             cblist = cblist->next;
01622       }
01623       list = list->next;
01624    }
01625     
01626    ast_mutex_unlock(&hintlock);
01627    return -1;
01628 }
01629 
01630 static int ast_add_hint(struct ast_exten *e)
01631 {
01632    struct ast_hint *list;
01633 
01634    if (!e) 
01635       return -1;
01636     
01637    ast_mutex_lock(&hintlock);
01638    list = hints;        
01639     
01640    /* Search if hint exists, do nothing */
01641    while (list) {
01642       if (list->exten == e) {
01643          ast_mutex_unlock(&hintlock);
01644          return -1;
01645       }
01646       list = list->next;    
01647       }
01648 
01649    list = malloc(sizeof(struct ast_hint));
01650    if (!list) {
01651       ast_mutex_unlock(&hintlock);
01652       return -1;
01653    }
01654    /* Initialize and insert new item */
01655    memset(list, 0, sizeof(struct ast_hint));
01656    list->exten = e;
01657    list->laststate = ast_extension_state2(e);
01658    list->next = hints;
01659    hints = list;
01660 
01661    ast_mutex_unlock(&hintlock);
01662    return 0;
01663 }
01664 
01665 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
01666 { 
01667    struct ast_hint *list;
01668 
01669    ast_mutex_lock(&hintlock);
01670    list = hints;
01671     
01672    while(list) {
01673       if (list->exten == oe) {
01674             list->exten = ne;
01675          ast_mutex_unlock(&hintlock);  
01676          return 0;
01677       }
01678       list = list->next;
01679    }
01680    ast_mutex_unlock(&hintlock);
01681 
01682    return -1;
01683 }
01684 
01685 static int ast_remove_hint(struct ast_exten *e)
01686 {
01687    /* Cleanup the Notifys if hint is removed */
01688    struct ast_hint *list, *prev = NULL;
01689    struct ast_state_cb *cblist, *cbprev;
01690 
01691    if (!e) 
01692       return -1;
01693 
01694    ast_mutex_lock(&hintlock);
01695 
01696    list = hints;    
01697    while(list) {
01698       if (list->exten==e) {
01699          cbprev = NULL;
01700          cblist = list->callbacks;
01701          while (cblist) {
01702             /* Notify with -1 and remove all callbacks */
01703             cbprev = cblist;      
01704             cblist = cblist->next;
01705             cbprev->callback(list->exten->parent->name, list->exten->exten, -1, cbprev->data);
01706             free(cbprev);
01707             }
01708             list->callbacks = NULL;
01709 
01710             if (!prev)
01711             hints = list->next;
01712             else
01713             prev->next = list->next;
01714             free(list);
01715        
01716          ast_mutex_unlock(&hintlock);
01717          return 0;
01718       } else {
01719          prev = list;
01720          list = list->next;    
01721       }
01722       }
01723 
01724    ast_mutex_unlock(&hintlock);
01725    return -1;
01726 }
01727 
01728 
01729 int ast_get_hint(char *hint, int hintsize, struct ast_channel *c, char *context, char *exten)
01730 {
01731    struct ast_exten *e;
01732    e = ast_hint_extension(c, context, exten);
01733    if (e) { 
01734        strncpy(hint, ast_get_extension_app(e), hintsize - 1);
01735        return -1;
01736    }
01737    return 0;   
01738 }
01739 
01740 int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
01741 {
01742    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_EXISTS);
01743 }
01744 
01745 int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
01746 {
01747    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_CANMATCH);
01748 }
01749 
01750 int ast_matchmore_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid)
01751 {
01752    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_MATCHMORE);
01753 }
01754 
01755 int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid) 
01756 {
01757    return pbx_extension_helper(c, context, exten, priority, callerid, HELPER_SPAWN);
01758 }
01759 
01760 int ast_pbx_run(struct ast_channel *c)
01761 {
01762    int firstpass = 1;
01763    char digit;
01764    char exten[256];
01765    int pos;
01766    int waittime;
01767    int res=0;
01768 
01769    /* A little initial setup here */
01770    if (c->pbx)
01771       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
01772    c->pbx = malloc(sizeof(struct ast_pbx));
01773    if (!c->pbx) {
01774       ast_log(LOG_ERROR, "Out of memory\n");
01775       return -1;
01776    }
01777    if (c->amaflags) {
01778       if (c->cdr) {
01779          ast_log(LOG_WARNING, "%s already has a call record??\n", c->name);
01780       } else {
01781          c->cdr = ast_cdr_alloc();
01782          if (!c->cdr) {
01783             ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01784             free(c->pbx);
01785             return -1;
01786          }
01787          ast_cdr_init(c->cdr, c);
01788       }
01789    }
01790    memset(c->pbx, 0, sizeof(struct ast_pbx));
01791    /* Set reasonable defaults */
01792    c->pbx->rtimeout = 10;
01793    c->pbx->dtimeout = 5;
01794 
01795    /* Start by trying whatever the channel is set to */
01796    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01797       /* JK02: If not successfull fall back to 's' */
01798       if (option_verbose > 1)
01799          ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
01800       strncpy(c->exten, "s", sizeof(c->exten)-1);
01801       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01802          /* JK02: And finally back to default if everything else failed */
01803          if (option_verbose > 1)
01804             ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
01805          strncpy(c->context, "default", sizeof(c->context)-1);
01806       }
01807       c->priority = 1;
01808    }
01809    if (c->cdr)
01810       ast_cdr_start(c->cdr);
01811    for(;;) {
01812       pos = 0;
01813       digit = 0;
01814       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01815          memset(exten, 0, sizeof(exten));
01816          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
01817             /* Something bad happened, or a hangup has been requested. */
01818             if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
01819                (res == '*') || (res == '#')) {
01820                ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
01821                memset(exten, 0, sizeof(exten));
01822                pos = 0;
01823                exten[pos++] = digit = res;
01824                break;
01825             }
01826             switch(res) {
01827             case AST_PBX_KEEPALIVE:
01828                if (option_debug)
01829                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
01830                else if (option_verbose > 1)
01831                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
01832                goto out;
01833                break;
01834             default:
01835                if (option_debug)
01836                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01837                else if (option_verbose > 1)
01838                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01839                if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
01840                   c->_softhangup =0;
01841                   break;
01842                }
01843                /* atimeout */
01844                if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
01845                   break;
01846                }
01847 
01848                if (c->cdr) {
01849                   ast_cdr_update(c);
01850                }
01851                goto out;
01852             }
01853          }
01854          if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->callerid))) {
01855             strncpy(c->exten,"T",sizeof(c->exten) - 1);
01856             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
01857             c->whentohangup = 0;
01858             c->priority = 0;
01859             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
01860          } else if (c->_softhangup) {
01861             ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
01862                c->exten, c->priority);
01863             goto out;
01864          }
01865          firstpass = 0;
01866          c->priority++;
01867       }
01868       if (!ast_exists_extension(c, c->context, c->exten, 1, c->callerid)) {
01869          /* It's not a valid extension anymore */
01870          if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
01871             if (option_verbose > 2)
01872                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
01873             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
01874             strncpy(c->exten, "i", sizeof(c->exten)-1);
01875             c->priority = 1;
01876          } else {
01877             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
01878                c->name, c->exten, c->context);
01879             goto out;
01880          }
01881       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
01882          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
01883          c->_softhangup = 0;
01884       } else {
01885          /* Done, wait for an extension */
01886          if (digit)
01887             waittime = c->pbx->dtimeout;
01888          else
01889             waittime = c->pbx->rtimeout;
01890          while (ast_matchmore_extension(c, c->context, exten, 1, c->callerid)) {
01891             /* As long as we're willing to wait, and as long as it's not defined, 
01892                keep reading digits until we can't possibly get a right answer anymore.  */
01893             digit = ast_waitfordigit(c, waittime * 1000);
01894             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
01895                c->_softhangup = 0;
01896             } else {
01897                if (!digit)
01898                   /* No entry */
01899                   break;
01900                if (digit < 0)
01901                   /* Error, maybe a  hangup */
01902                   goto out;
01903                exten[pos++] = digit;
01904                waittime = c->pbx->dtimeout;
01905             }
01906          }
01907          if (ast_exists_extension(c, c->context, exten, 1, c->callerid)) {
01908             /* Prepare the next cycle */
01909             strncpy(c->exten, exten, sizeof(c->exten)-1);
01910             c->priority = 1;
01911          } else {
01912             /* No such extension */
01913             if (!ast_strlen_zero(exten)) {
01914                /* An invalid extension */
01915                if (ast_exists_extension(c, c->context, "i", 1, c->callerid)) {
01916                   if (option_verbose > 2)
01917                      ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
01918                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
01919                   strncpy(c->exten, "i", sizeof(c->exten)-1);
01920                   c->priority = 1;
01921                } else {
01922                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
01923                   goto out;
01924                }
01925             } else {
01926                /* A simple timeout */
01927                if (ast_exists_extension(c, c->context, "t", 1, c->callerid)) {
01928                   if (option_verbose > 2)
01929                      ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
01930                   strncpy(c->exten, "t", sizeof(c->exten)-1);
01931                   c->priority = 1;
01932                } else {
01933                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
01934                   goto out;
01935                }
01936             }  
01937          }
01938          if (c->cdr) {
01939             if (option_verbose > 2)
01940                ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);   
01941             ast_cdr_update(c);
01942           }
01943       }
01944    }
01945    if (firstpass) 
01946       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
01947 out:
01948    if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->callerid)) {
01949       c->exten[0] = 'h';
01950       c->exten[1] = '\0';
01951       c->priority = 1;
01952       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
01953          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
01954             /* Something bad happened, or a hangup has been requested. */
01955             if (option_debug)
01956                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01957             else if (option_verbose > 1)
01958                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
01959             break;
01960          }
01961          c->priority++;
01962       }
01963    }
01964 
01965    pbx_destroy(c->pbx);
01966    c->pbx = NULL;
01967    if (res != AST_PBX_KEEPALIVE)
01968       ast_hangup(c);
01969    return 0;
01970 }
01971 
01972 static void *pbx_thread(void *data)
01973 {
01974    /* Oh joyeous kernel, we're a new thread, with nothing to do but
01975       answer this channel and get it going.  The setjmp stuff is fairly
01976       confusing, but necessary to get smooth transitions between
01977       the execution of different applications (without the use of
01978       additional threads) */
01979    struct ast_channel *c = data;
01980    ast_pbx_run(c);
01981    pthread_exit(NULL);
01982    return NULL;
01983 }
01984 
01985 int ast_pbx_start(struct ast_channel *c)
01986 {
01987    pthread_t t;
01988    pthread_attr_t attr;
01989    if (!c) {
01990       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
01991       return -1;
01992    }
01993       
01994    /* Start a new thread, and get something handling this channel. */
01995    pthread_attr_init(&attr);
01996    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
01997    if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
01998       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
01999       return -1;
02000    }
02001    return 0;
02002 }
02003 
02004 /*
02005  * This function locks contexts list by &conlist, search for the right context
02006  * structure, leave context list locked and call ast_context_remove_include2
02007  * which removes include, unlock contexts list and return ...
02008  */
02009 int ast_context_remove_include(char *context, char *include, char *registrar)
02010 {
02011    struct ast_context *c;
02012 
02013    if (ast_lock_contexts()) return -1;
02014 
02015    /* walk contexts and search for the right one ...*/
02016    c = ast_walk_contexts(NULL);
02017    while (c) {
02018       /* we found one ... */
02019       if (!strcmp(ast_get_context_name(c), context)) {
02020          int ret;
02021          /* remove include from this context ... */   
02022          ret = ast_context_remove_include2(c, include, registrar);
02023 
02024          ast_unlock_contexts();
02025 
02026          /* ... return results */
02027          return ret;
02028       }
02029       c = ast_walk_contexts(c);
02030    }
02031 
02032    /* we can't find the right one context */
02033    ast_unlock_contexts();
02034    return -1;
02035 }
02036 
02037 /*
02038  * When we call this function, &conlock lock must be locked, because when
02039  * we giving *con argument, some process can remove/change this context
02040  * and after that there can be segfault.
02041  *
02042  * This function locks given context, removes include, unlock context and
02043  * return.
02044  */
02045 int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar)
02046 {
02047    struct ast_include *i, *pi = NULL;
02048 
02049    if (ast_mutex_lock(&con->lock)) return -1;
02050 
02051    /* walk includes */
02052    i = con->includes;
02053    while (i) {
02054       /* find our include */
02055       if (!strcmp(i->name, include) && 
02056          (!registrar || !strcmp(i->registrar, registrar))) {
02057          /* remove from list */
02058          if (pi)
02059             pi->next = i->next;
02060          else
02061             con->includes = i->next;
02062          /* free include and return */
02063          free(i);
02064          ast_mutex_unlock(&con->lock);
02065          return 0;
02066       }
02067       pi = i;
02068       i = i->next;
02069    }
02070 
02071    /* we can't find the right include */
02072    ast_mutex_unlock(&con->lock);
02073    return -1;
02074 }
02075 
02076 /*
02077  * This function locks contexts list by &conlist, search for the rigt context
02078  * structure, leave context list locked and call ast_context_remove_switch2
02079  * which removes switch, unlock contexts list and return ...
02080  */
02081 int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar)
02082 {
02083    struct ast_context *c;
02084 
02085    if (ast_lock_contexts()) return -1;
02086 
02087    /* walk contexts and search for the right one ...*/
02088    c = ast_walk_contexts(NULL);
02089    while (c) {
02090       /* we found one ... */
02091       if (!strcmp(ast_get_context_name(c), context)) {
02092          int ret;
02093          /* remove switch from this context ... */ 
02094          ret = ast_context_remove_switch2(c, sw, data, registrar);
02095 
02096          ast_unlock_contexts();
02097 
02098          /* ... return results */
02099          return ret;
02100       }
02101       c = ast_walk_contexts(c);
02102    }
02103 
02104    /* we can't find the right one context */
02105    ast_unlock_contexts();
02106    return -1;
02107 }
02108 
02109 /*
02110  * When we call this function, &conlock lock must be locked, because when
02111  * we giving *con argument, some process can remove/change this context
02112  * and after that there can be segfault.
02113  *
02114  * This function locks given context, removes switch, unlock context and
02115  * return.
02116  */
02117 int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar)
02118 {
02119    struct ast_sw *i, *pi = NULL;
02120 
02121    if (ast_mutex_lock(&con->lock)) return -1;
02122 
02123    /* walk switchs */
02124    i = con->alts;
02125    while (i) {
02126       /* find our switch */
02127       if (!strcmp(i->name, sw) && !strcmp(i->data, data) && 
02128          (!registrar || !strcmp(i->registrar, registrar))) {
02129          /* remove from list */
02130          if (pi)
02131             pi->next = i->next;
02132          else
02133             con->alts = i->next;
02134          /* free switch and return */
02135          free(i);
02136          ast_mutex_unlock(&con->lock);
02137          return 0;
02138       }
02139       pi = i;
02140       i = i->next;
02141    }
02142 
02143    /* we can't find the right switch */
02144    ast_mutex_unlock(&con->lock);
02145    return -1;
02146 }
02147 
02148 /*
02149  * This functions lock contexts list, search for the right context,
02150  * call ast_context_remove_extension2, unlock contexts list and return.
02151  * In this function we are using
02152  */
02153 int ast_context_remove_extension(char *context, char *extension, int priority, char *registrar)
02154 {
02155    struct ast_context *c;
02156 
02157    if (ast_lock_contexts()) return -1;
02158 
02159    /* walk contexts ... */
02160    c = ast_walk_contexts(NULL);
02161    while (c) {
02162       /* ... search for the right one ... */
02163       if (!strcmp(ast_get_context_name(c), context)) {
02164          /* ... remove extension ... */
02165          int ret = ast_context_remove_extension2(c, extension, priority,
02166             registrar);
02167          /* ... unlock contexts list and return */
02168          ast_unlock_contexts();
02169          return ret;
02170       }
02171       c = ast_walk_contexts(c);
02172    }
02173 
02174    /* we can't find the right context */
02175    ast_unlock_contexts();
02176    return -1;
02177 }
02178 
02179 /*
02180  * When do you want to call this function, make sure that &conlock is locked,
02181  * because some process can handle with your *con context before you lock
02182  * it.
02183  *
02184  * This functionc locks given context, search for the right extension and
02185  * fires out all peer in this extensions with given priority. If priority
02186  * is set to 0, all peers are removed. After that, unlock context and
02187  * return.
02188  */
02189 int ast_context_remove_extension2(struct ast_context *con, char *extension, int priority, char *registrar)
02190 {
02191    struct ast_exten *exten, *prev_exten = NULL;
02192 
02193    if (ast_mutex_lock(&con->lock)) return -1;
02194 
02195    /* go through all extensions in context and search the right one ... */
02196    exten = con->root;
02197    while (exten) {
02198 
02199       /* look for right extension */
02200       if (!strcmp(exten->exten, extension) &&
02201          (!registrar || !strcmp(exten->registrar, registrar))) {
02202          struct ast_exten *peer;
02203 
02204          /* should we free all peers in this extension? (priority == 0)? */
02205          if (priority == 0) {
02206             /* remove this extension from context list */
02207             if (prev_exten)
02208                prev_exten->next = exten->next;
02209             else
02210                con->root = exten->next;
02211 
02212             /* fire out all peers */
02213             peer = exten; 
02214             while (peer) {
02215                exten = peer->peer;
02216                
02217                if (!peer->priority==PRIORITY_HINT) 
02218                    ast_remove_hint(peer);
02219 
02220                peer->datad(peer->data);
02221                free(peer);
02222 
02223                peer = exten;
02224             }
02225 
02226             ast_mutex_unlock(&con->lock);
02227             return 0;
02228          } else {
02229             /* remove only extension with exten->priority == priority */
02230             struct ast_exten *previous_peer = NULL;
02231 
02232             peer = exten;
02233             while (peer) {
02234                /* is this our extension? */
02235                if (peer->priority == priority &&
02236                   (!registrar || !strcmp(peer->registrar, registrar) )) {
02237                   /* we are first priority extension? */
02238                   if (!previous_peer) {
02239                      /* exists previous extension here? */
02240                      if (prev_exten) {
02241                         /* yes, so we must change next pointer in
02242                          * previous connection to next peer
02243                          */
02244                         if (peer->peer) {
02245                            prev_exten->next = peer->peer;
02246                            peer->peer->next = exten->next;
02247                         } else
02248                            prev_exten->next = exten->next;
02249                      } else {
02250                         /* no previous extension, we are first
02251                          * extension, so change con->root ...
02252                          */
02253                         if (peer->peer)
02254                            con->root = peer->peer;
02255                         else
02256                            con->root = exten->next; 
02257                      }
02258                   } else {
02259                      /* we are not first priority in extension */
02260                      previous_peer->peer = peer->peer;
02261                   }
02262 
02263                   /* now, free whole priority extension */
02264                   if (peer->priority==PRIORITY_HINT)
02265                       ast_remove_hint(peer);
02266                   peer->datad(peer->data);
02267                   free(peer);
02268 
02269                   ast_mutex_unlock(&con->lock);
02270                   return 0;
02271                } else {
02272                   /* this is not right extension, skip to next peer */
02273                   previous_peer = peer;
02274                   peer = peer->peer;
02275                }
02276             }
02277 
02278             ast_mutex_unlock(&con->lock);
02279             return -1;
02280          }
02281       }
02282 
02283       prev_exten = exten;
02284       exten = exten->next;
02285    }
02286 
02287    /* we can't find right extension */
02288    ast_mutex_unlock(&con->lock);
02289    return -1;
02290 }
02291 
02292 
02293 int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *), char *synopsis, char *description)
02294 {
02295    struct ast_app *tmp, *prev, *cur;
02296    char tmps[80];
02297    if (ast_mutex_lock(&applock)) {
02298       ast_log(LOG_ERROR, "Unable to lock application list\n");
02299       return -1;
02300    }
02301    tmp = apps;
02302    while(tmp) {
02303       if (!strcasecmp(app, tmp->name)) {
02304          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02305          ast_mutex_unlock(&applock);
02306          return -1;
02307       }
02308       tmp = tmp->next;
02309    }
02310    tmp = malloc(sizeof(struct ast_app));
02311    if (tmp) {
02312       memset(tmp, 0, sizeof(struct ast_app));
02313       strncpy(tmp->name, app, sizeof(tmp->name)-1);
02314       tmp->execute = execute;
02315       tmp->synopsis = synopsis;
02316       tmp->description = description;
02317       /* Store in alphabetical order */
02318       cur = apps;
02319       prev = NULL;
02320       while(cur) {
02321          if (strcasecmp(tmp->name, cur->name) < 0)
02322             break;
02323          prev = cur;
02324          cur = cur->next;
02325       }
02326       if (prev) {
02327          tmp->next = prev->next;
02328          prev->next = tmp;
02329       } else {
02330          tmp->next = apps;
02331          apps = tmp;
02332       }
02333    } else {
02334       ast_log(LOG_ERROR, "Out of memory\n");
02335       ast_mutex_unlock(&applock);
02336       return -1;
02337    }
02338    if (option_verbose > 1)
02339       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02340    ast_mutex_unlock(&applock);
02341    return 0;
02342 }
02343 
02344 int ast_register_switch(struct ast_switch *sw)
02345 {
02346    struct ast_switch *tmp, *prev=NULL;
02347    if (ast_mutex_lock(&switchlock)) {
02348       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02349       return -1;
02350    }
02351    tmp = switches;
02352    while(tmp) {
02353       if (!strcasecmp(tmp->name, sw->name))
02354          break;
02355       prev = tmp;
02356       tmp = tmp->next;
02357    }
02358    if (tmp) {  
02359       ast_mutex_unlock(&switchlock);
02360       ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
02361       return -1;
02362    }
02363    sw->next = NULL;
02364    if (prev) 
02365       prev->next = sw;
02366    else
02367       switches = sw;
02368    ast_mutex_unlock(&switchlock);
02369    return 0;
02370 }
02371 
02372 void ast_unregister_switch(struct ast_switch *sw)
02373 {
02374    struct ast_switch *tmp, *prev=NULL;
02375    if (ast_mutex_lock(&switchlock)) {
02376       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
02377       return;
02378    }
02379    tmp = switches;
02380    while(tmp) {
02381       if (tmp == sw) {
02382          if (prev)
02383             prev->next = tmp->next;
02384          else
02385             switches = tmp->next;
02386          tmp->next = NULL;
02387          break;         
02388       }
02389       prev = tmp;
02390       tmp = tmp->next;
02391    }
02392    ast_mutex_unlock(&switchlock);
02393 }
02394 
02395 /*
02396  * Help for CLI commands ...
02397  */
02398 static char show_application_help[] = 
02399 "Usage: show application <application> [<application> [<application> [...]]]\n"
02400 "       Describes a particular application.\n";
02401 
02402 static char show_applications_help[] =
02403 "Usage: show applications [{like|describing} <text>]\n"
02404 "       List applications which are currently available.\n"
02405 "       If 'like', <text> will be a substring of the app name\n"
02406 "       If 'describing', <text> will be a substring of the description\n";
02407 
02408 static char show_dialplan_help[] =
02409 "Usage: show dialplan [exten@][context]\n"
02410 "       Show dialplan\n";
02411 
02412 static char show_switches_help[] = 
02413 "Usage: show switches\n"
02414 "       Show registered switches\n";
02415 
02416 /*
02417  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
02418  *
02419  */
02420 
02421 /*
02422  * 'show application' CLI command implementation functions ...
02423  */
02424 
02425 /*
02426  * There is a possibility to show informations about more than one
02427  * application at one time. You can type 'show application Dial Echo' and
02428  * you will see informations about these two applications ...
02429  */
02430 static char *complete_show_application(char *line, char *word,
02431    int pos, int state)
02432 {
02433    struct ast_app *a;
02434    int which = 0;
02435 
02436    /* try to lock applications list ... */
02437    if (ast_mutex_lock(&applock)) {
02438       ast_log(LOG_ERROR, "Unable to lock application list\n");
02439       return NULL;
02440    }
02441 
02442    /* ... walk all applications ... */
02443    a = apps; 
02444    while (a) {
02445       /* ... check if word matches this application ... */
02446       if (!strncasecmp(word, a->name, strlen(word))) {
02447          /* ... if this is right app serve it ... */
02448          if (++which > state) {
02449             char *ret = strdup(a->name);
02450             ast_mutex_unlock(&applock);
02451             return ret;
02452          }
02453       }
02454       a = a->next; 
02455    }
02456 
02457    /* no application match */
02458    ast_mutex_unlock(&applock);
02459    return NULL; 
02460 }
02461 
02462 static int handle_show_application(int fd, int argc, char *argv[])
02463 {
02464    struct ast_app *a;
02465    int app, no_registered_app = 1;
02466 
02467    if (argc < 3) return RESULT_SHOWUSAGE;
02468 
02469    /* try to lock applications list ... */
02470    if (ast_mutex_lock(&applock)) {
02471       ast_log(LOG_ERROR, "Unable to lock application list\n");
02472       return -1;
02473    }
02474 
02475    /* ... go through all applications ... */
02476    a = apps; 
02477    while (a) {
02478       /* ... compare this application name with all arguments given
02479        * to 'show application' command ... */
02480       for (app = 2; app < argc; app++) {
02481          if (!strcasecmp(a->name, argv[app])) {
02482             /* Maximum number of characters added by terminal coloring is 22 */
02483             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02484             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02485             int synopsis_size, description_size;
02486 
02487             no_registered_app = 0;
02488 
02489             if (a->synopsis)
02490                synopsis_size = strlen(a->synopsis) + 23;
02491             else
02492                synopsis_size = strlen("Not available") + 23;
02493             synopsis = alloca(synopsis_size);
02494 
02495             if (a->description)
02496                description_size = strlen(a->description) + 23;
02497             else
02498                description_size = strlen("Not available") + 23;
02499             description = alloca(description_size);
02500 
02501             if (synopsis && description) {
02502                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
02503                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02504                term_color(syntitle, "[Synopsis]:\n", COLOR_MAGENTA, 0, 40);
02505                term_color(destitle, "[Description]:\n", COLOR_MAGENTA, 0, 40);
02506                term_color(synopsis,
02507                            a->synopsis ? a->synopsis : "Not available",
02508                            COLOR_CYAN, 0, synopsis_size);
02509                term_color(description,
02510                            a->description ? a->description : "Not available",
02511                            COLOR_CYAN, 0, description_size);
02512 
02513                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
02514             } else {
02515                /* ... one of our applications, show info ...*/
02516                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
02517                   "[Synopsis]:\n  %s\n\n"
02518                   "[Description]:\n%s\n",
02519                   a->name,
02520                   a->synopsis ? a->synopsis : "Not available",
02521                   a->description ? a->description : "Not available");
02522             }
02523          }
02524       }
02525       a = a->next; 
02526    }
02527 
02528    ast_mutex_unlock(&applock);
02529 
02530    /* we found at least one app? no? */
02531    if (no_registered_app) {
02532       ast_cli(fd, "Your application(s) is (are) not registered\n");
02533       return RESULT_FAILURE;
02534    }
02535 
02536    return RESULT_SUCCESS;
02537 }
02538 
02539 static int handle_show_switches(int fd, int argc, char *argv[])
02540 {
02541    struct ast_switch *sw;
02542    if (!switches) {
02543       ast_cli(fd, "There are no registered alternative switches\n");
02544       return RESULT_SUCCESS;
02545    }
02546    /* ... we have applications ... */
02547    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
02548    if (ast_mutex_lock(&switchlock)) {
02549       ast_log(LOG_ERROR, "Unable to lock switches\n");
02550       return -1;
02551    }
02552    sw = switches;
02553    while (sw) {
02554       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
02555       sw = sw->next;
02556    }
02557    ast_mutex_unlock(&switchlock);
02558    return RESULT_SUCCESS;
02559 }
02560 
02561 /*
02562  * 'show applications' CLI command implementation functions ...
02563  */
02564 static int handle_show_applications(int fd, int argc, char *argv[])
02565 {
02566    struct ast_app *a;
02567    int like=0, describing=0;
02568 
02569    /* try to lock applications list ... */
02570    if (ast_mutex_lock(&applock)) {
02571       ast_log(LOG_ERROR, "Unable to lock application list\n");
02572       return -1;
02573    }
02574 
02575    /* ... have we got at least one application (first)? no? */
02576    if (!apps) {
02577       ast_cli(fd, "There are no registered applications\n");
02578       ast_mutex_unlock(&applock);
02579       return -1;
02580    }
02581 
02582    /* show applications like <keyword> */
02583    if ((argc == 4) && (!strcmp(argv[2], "like"))) {
02584       like = 1;
02585    } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
02586       describing = 1;
02587    }
02588 
02589    /* show applications describing <keyword1> [<keyword2>] [...] */
02590    if ((!like) && (!describing)) {
02591       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
02592    } else {
02593       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
02594    }
02595 
02596    /* ... go through all applications ... */
02597    for (a = apps; a; a = a->next) {
02598       /* ... show informations about applications ... */
02599       int printapp=0;
02600 
02601       if (like) {
02602          if (ast_strcasestr(a->name, argv[3])) {
02603             printapp = 1;
02604          }
02605       } else if (describing) {
02606          if (a->description) {
02607             /* Match all words on command line */
02608             int i;
02609             printapp = 1;
02610             for (i=3;i<argc;i++) {
02611                if (! ast_strcasestr(a->description, argv[i])) {
02612                   printapp = 0;
02613                }
02614             }
02615          }
02616       } else {
02617          printapp = 1;
02618       }
02619 
02620       if (printapp) {
02621          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
02622       }
02623    }
02624 
02625    /* ... unlock and return */
02626    ast_mutex_unlock(&applock);
02627 
02628    return RESULT_SUCCESS;
02629 }
02630 
02631 static char *complete_show_applications(char *line, char *word, int pos, int state)
02632 {
02633    if (pos == 2) {
02634       if (ast_strlen_zero(word)) {
02635          switch (state) {
02636          case 0:
02637             return strdup("like");
02638          case 1:
02639             return strdup("describing");
02640          default:
02641             return NULL;
02642          }
02643       } else if (! strncasecmp(word, "like", strlen(word))) {
02644          if (state == 0) {
02645             return strdup("like");
02646          } else {
02647             return NULL;
02648          }
02649       } else if (! strncasecmp(word, "describing", strlen(word))) {
02650          if (state == 0) {
02651             return strdup("describing");
02652          } else {
02653             return NULL;
02654          }
02655       }
02656    }
02657    return NULL;
02658 }
02659 
02660 /*
02661  * 'show dialplan' CLI command implementation functions ...
02662  */
02663 static char *complete_show_dialplan_context(char *line, char *word, int pos,
02664    int state)
02665 {
02666    struct ast_context *c;
02667    int which = 0;
02668 
02669    /* we are do completion of [exten@]context on second position only */
02670    if (pos != 2) return NULL;
02671 
02672    /* try to lock contexts list ... */
02673    if (ast_lock_contexts()) {
02674       ast_log(LOG_ERROR, "Unable to lock context list\n");
02675       return NULL;
02676    }
02677 
02678    /* ... walk through all contexts ... */
02679    c = ast_walk_contexts(NULL);
02680    while(c) {
02681       /* ... word matches context name? yes? ... */
02682       if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
02683          /* ... for serve? ... */
02684          if (++which > state) {
02685             /* ... yes, serve this context name ... */
02686             char *ret = strdup(ast_get_context_name(c));
02687             ast_unlock_contexts();
02688             return ret;
02689          }
02690       }
02691       c = ast_walk_contexts(c);
02692    }
02693 
02694    /* ... unlock and return */
02695    ast_unlock_contexts();
02696    return NULL;
02697 }
02698 
02699 static int handle_show_dialplan(int fd, int argc, char *argv[])
02700 {
02701    struct ast_context *c;
02702    char *exten = NULL, *context = NULL;
02703    int context_existence = 0, extension_existence = 0;
02704 
02705    if (argc != 3 && argc != 2) return -1;
02706 
02707    /* we obtain [exten@]context? if yes, split them ... */
02708    if (argc == 3) {
02709       char *splitter = argv[2];
02710       /* is there a '@' character? */
02711       if (strchr(argv[2], '@')) {
02712          /* yes, split into exten & context ... */
02713          exten   = strsep(&splitter, "@");
02714          context = splitter;
02715 
02716          /* check for length and change to NULL if ast_strlen_zero() */
02717          if (ast_strlen_zero(exten))   exten = NULL;
02718          if (ast_strlen_zero(context)) context = NULL;
02719       } else
02720       {
02721          /* no '@' char, only context given */
02722          context = argv[2];
02723          if (ast_strlen_zero(context)) context = NULL;
02724       }
02725    }
02726 
02727    /* try to lock contexts */
02728    if (ast_lock_contexts()) {
02729       ast_log(LOG_WARNING, "Failed to lock contexts list\n");
02730       return RESULT_FAILURE;
02731    }
02732 
02733    /* walk all contexts ... */
02734    c = ast_walk_contexts(NULL);
02735    while (c) {
02736       /* show this context? */
02737       if (!context ||
02738          !strcmp(ast_get_context_name(c), context)) {
02739          context_existence = 1;
02740 
02741          /* try to lock context before walking in ... */
02742          if (!ast_lock_context(c)) {
02743             struct ast_exten *e;
02744             struct ast_include *i;
02745             struct ast_ignorepat *ip;
02746             struct ast_sw *sw;
02747             char buf[256], buf2[256];
02748             int context_info_printed = 0;
02749 
02750             /* are we looking for exten too? if yes, we print context
02751              * if we our extension only
02752              */
02753             if (!exten) {
02754                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
02755                   ast_get_context_name(c), ast_get_context_registrar(c));
02756                context_info_printed = 1;
02757             }
02758 
02759             /* walk extensions ... */
02760             e = ast_walk_context_extensions(c, NULL);
02761             while (e) {
02762                struct ast_exten *p;
02763 
02764                /* looking for extension? is this our extension? */
02765                if (exten &&
02766                   strcmp(ast_get_extension_name(e), exten))
02767                {
02768                   /* we are looking for extension and it's not our
02769                    * extension, so skip to next extension */
02770                   e = ast_walk_context_extensions(c, e);
02771                   continue;
02772                }
02773 
02774                extension_existence = 1;
02775 
02776                /* may we print context info? */ 
02777                if (!context_info_printed) {
02778                   ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
02779                      ast_get_context_name(c),
02780                      ast_get_context_registrar(c));
02781                   context_info_printed = 1;
02782                }
02783 
02784                /* write extension name and first peer */ 
02785                bzero(buf, sizeof(buf));      
02786                snprintf(buf, sizeof(buf), "'%s' =>",
02787                   ast_get_extension_name(e));
02788 
02789                snprintf(buf2, sizeof(buf2),
02790                   "%d. %s(%s)",
02791                   ast_get_extension_priority(e),
02792                   ast_get_extension_app(e),
02793                   (char *)ast_get_extension_app_data(e));
02794 
02795                ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
02796                   ast_get_extension_registrar(e));
02797 
02798                /* walk next extension peers */
02799                p = ast_walk_extension_priorities(e, e);
02800                while (p) {
02801                   bzero((void *)buf2, sizeof(buf2));
02802 
02803                   snprintf(buf2, sizeof(buf2),
02804                      "%d. %s(%s)",
02805                      ast_get_extension_priority(p),
02806                      ast_get_extension_app(p),
02807                      (char *)ast_get_extension_app_data(p));
02808 
02809                   ast_cli(fd,"  %-17s %-45s [%s]\n",
02810                      "", buf2,
02811                      ast_get_extension_registrar(p)); 
02812 
02813                   p = ast_walk_extension_priorities(e, p);
02814                }
02815                e = ast_walk_context_extensions(c, e);
02816             }
02817 
02818             /* include & ignorepat we all printing if we are not
02819              * looking for exact extension
02820              */
02821             if (!exten) {
02822                if (ast_walk_context_extensions(c, NULL))
02823                   ast_cli(fd, "\n");
02824 
02825                /* walk included and write info ... */
02826                i = ast_walk_context_includes(c, NULL);
02827                while (i) {
02828                   bzero(buf, sizeof(buf));
02829                   snprintf(buf, sizeof(buf), "'%s'",
02830                      ast_get_include_name(i));
02831                   ast_cli(fd, "  Include =>        %-45s [%s]\n",
02832                      buf, ast_get_include_registrar(i));
02833                   i = ast_walk_context_includes(c, i);
02834                }
02835 
02836                /* walk ignore patterns and write info ... */
02837                ip = ast_walk_context_ignorepats(c, NULL);
02838                while (ip) {
02839                   bzero(buf, sizeof(buf));
02840                   snprintf(buf, sizeof(buf), "'%s'",
02841                      ast_get_ignorepat_name(ip));
02842                   ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
02843                      buf, ast_get_ignorepat_registrar(ip)); 
02844                   ip = ast_walk_context_ignorepats(c, ip);
02845                }
02846                sw = ast_walk_context_switches(c, NULL);
02847                while(sw) {
02848                   bzero(buf, sizeof(buf));
02849                   snprintf(buf, sizeof(buf), "'%s/%s'",
02850                      ast_get_switch_name(sw),
02851                      ast_get_switch_data(sw));
02852                   ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
02853                      buf, ast_get_switch_registrar(sw)); 
02854                   sw = ast_walk_context_switches(c, sw);
02855                }
02856             }
02857    
02858             ast_unlock_context(c);
02859 
02860             /* if we print something in context, make an empty line */
02861             if (context_info_printed) ast_cli(fd, "\n");
02862          }
02863       }
02864       c = ast_walk_contexts(c);
02865    }
02866    ast_unlock_contexts();
02867 
02868    /* check for input failure and throw some error messages */
02869    if (context && !context_existence) {
02870       ast_cli(fd, "There is no existence of '%s' context\n",
02871          context);
02872       return RESULT_FAILURE;
02873    }
02874 
02875    if (exten && !extension_existence) {
02876       if (context)
02877          ast_cli(fd, "There is no existence of %s@%s extension\n",
02878             exten, context);
02879       else
02880          ast_cli(fd,
02881             "There is no existence of '%s' extension in all contexts\n",
02882             exten);
02883       return RESULT_FAILURE;
02884    }
02885 
02886    /* everything ok */
02887    return RESULT_SUCCESS;
02888 }
02889 
02890 /*
02891  * CLI entries for upper commands ...
02892  */
02893 static struct ast_cli_entry show_applications_cli = 
02894    { { "show", "applications", NULL }, 
02895    handle_show_applications, "Shows registered applications",
02896    show_applications_help, complete_show_applications };
02897 
02898 static struct ast_cli_entry show_application_cli =
02899    { { "show", "application", NULL }, 
02900    handle_show_application, "Describe a specific application",
02901    show_application_help, complete_show_application };
02902 
02903 static struct ast_cli_entry show_dialplan_cli =
02904    { { "show", "dialplan", NULL },
02905       handle_show_dialplan, "Show dialplan",
02906       show_dialplan_help, complete_show_dialplan_context };
02907 
02908 static struct ast_cli_entry show_switches_cli =
02909    { { "show", "switches", NULL },
02910       handle_show_switches, "Show alternative switches",
02911       show_switches_help, NULL };
02912 
02913 int ast_unregister_application(char *app) {
02914    struct ast_app *tmp, *tmpl = NULL;
02915    if (ast_mutex_lock(&applock)) {
02916       ast_log(LOG_ERROR, "Unable to lock application list\n");
02917       return -1;
02918    }
02919    tmp = apps;
02920    while(tmp) {
02921       if (!strcasecmp(app, tmp->name)) {
02922          if (tmpl)
02923             tmpl->next = tmp->next;
02924          else
02925             apps = tmp->next;
02926          if (option_verbose > 1)
02927             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
02928          free(tmp);
02929          ast_mutex_unlock(&applock);
02930          return 0;
02931       }
02932       tmpl = tmp;
02933       tmp = tmp->next;
02934    }
02935    ast_mutex_unlock(&applock);
02936    return -1;
02937 }
02938 
02939 struct ast_context *ast_context_create(struct ast_context **extcontexts, char *name, char *registrar)
02940 {
02941    struct ast_context *tmp, **local_contexts;
02942    if (!extcontexts) {
02943       local_contexts = &contexts;
02944       ast_mutex_lock(&conlock);
02945    } else
02946       local_contexts = extcontexts;
02947 
02948    tmp = *local_contexts;
02949    while(tmp) {
02950       if (!strcasecmp(tmp->name, name)) {
02951          ast_mutex_unlock(&conlock);
02952          ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
02953          if (!extcontexts)
02954             ast_mutex_unlock(&conlock);
02955          return NULL;
02956       }
02957       tmp = tmp->next;
02958    }
02959    tmp = malloc(sizeof(struct ast_context));
02960    if (tmp) {
02961       memset(tmp, 0, sizeof(struct ast_context));
02962       ast_mutex_init(&tmp->lock);
02963       strncpy(tmp->name, name, sizeof(tmp->name)-1);
02964       tmp->root = NULL;
02965       tmp->registrar = registrar;
02966       tmp->next = *local_contexts;
02967       tmp->includes = NULL;
02968       tmp->ignorepats = NULL;
02969       *local_contexts = tmp;
02970       if (option_debug)
02971          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
02972       else if (option_verbose > 2)
02973          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
02974    } else
02975       ast_log(LOG_ERROR, "Out of memory\n");
02976    
02977    if (!extcontexts)
02978       ast_mutex_unlock(&conlock);
02979    return tmp;
02980 }
02981 
02982 void __ast_context_destroy(struct ast_context *con, char *registrar);
02983 
02984 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, char *registrar) {
02985    struct ast_context *tmp, *lasttmp = NULL;
02986    tmp = *extcontexts;
02987    ast_mutex_lock(&conlock);
02988    if (registrar) {
02989       __ast_context_destroy(NULL,registrar);
02990       while (tmp) {
02991          lasttmp = tmp;
02992          tmp = tmp->next;
02993       }
02994    } else {
02995       while (tmp) {
02996          __ast_context_destroy(tmp,tmp->registrar);
02997          lasttmp = tmp;
02998          tmp = tmp->next;
02999       }
03000    }
03001    if (lasttmp) {
03002       lasttmp->next = contexts;
03003       contexts = *extcontexts;
03004       *extcontexts = NULL;
03005    } else 
03006       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
03007    ast_mutex_unlock(&conlock);
03008    return;  
03009 }
03010 
03011 /*
03012  * errno values
03013  *  EBUSY  - can't lock
03014  *  ENOENT - no existence of context
03015  */
03016 int ast_context_add_include(char *context, char *include, char *registrar)
03017 {
03018    struct ast_context *c;
03019 
03020    if (ast_lock_contexts()) {
03021       errno = EBUSY;
03022       return -1;
03023    }
03024 
03025    /* walk contexts ... */
03026    c = ast_walk_contexts(NULL);
03027    while (c) {
03028       /* ... search for the right one ... */
03029       if (!strcmp(ast_get_context_name(c), context)) {
03030          int ret = ast_context_add_include2(c, include, registrar);
03031          /* ... unlock contexts list and return */
03032          ast_unlock_contexts();
03033          return ret;
03034       }
03035       c = ast_walk_contexts(c);
03036    }
03037 
03038    /* we can't find the right context */
03039    ast_unlock_contexts();
03040    errno = ENOENT;
03041    return -1;
03042 }
03043 
03044 #define FIND_NEXT \
03045 do { \
03046    c = info; \
03047    while(*c && (*c != '|')) c++; \
03048    if (*c) { *c = '\0'; c++; } else c = NULL; \
03049 } while(0)
03050 
03051 static void get_timerange(struct ast_include *i, char *times)
03052 {
03053    char *e;
03054    int x;
03055    int s1, s2;
03056    int e1, e2;
03057    /* int cth, ctm; */
03058 
03059    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
03060    memset(i->minmask, 0, sizeof(i->minmask));
03061    
03062    /* Star is all times */
03063    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
03064       for (x=0;x<24;x++)
03065          i->minmask[x] = (1 << 30) - 1;
03066       return;
03067    }
03068    /* Otherwise expect a range */
03069    e = strchr(times, '-');
03070    if (!e) {
03071       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
03072       return;
03073    }
03074    *e = '\0';
03075    e++;
03076    while(*e && !isdigit(*e)) e++;
03077    if (!*e) {
03078       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
03079       return;
03080    }
03081    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
03082       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
03083       return;
03084    }
03085    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
03086       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
03087       return;
03088    }
03089 
03090 #if 1
03091    s1 = s1 * 30 + s2/2;
03092    if ((s1 < 0) || (s1 >= 24*30)) {
03093       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
03094       return;
03095    }
03096    e1 = e1 * 30 + e2/2;
03097    if ((e1 < 0) || (e1 >= 24*30)) {
03098       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
03099       return;
03100    }
03101    /* Go through the time and enable each appropriate bit */
03102    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
03103       i->minmask[x/30] |= (1 << (x % 30));
03104    }
03105    /* Do the last one */
03106    i->minmask[x/30] |= (1 << (x % 30));
03107 #else
03108    for (cth=0;cth<24;cth++) {
03109       /* Initialize masks to blank */
03110       i->minmask[cth] = 0;
03111       for (ctm=0;ctm<30;ctm++) {
03112          if (
03113          /* First hour with more than one hour */
03114                (((cth == s1) && (ctm >= s2)) &&
03115                 ((cth < e1)))
03116          /* Only one hour */
03117          ||    (((cth == s1) && (ctm >= s2)) &&
03118                 ((cth == e1) && (ctm <= e2)))
03119          /* In between first and last hours (more than 2 hours) */
03120          ||    ((cth > s1) &&
03121                 (cth < e1))
03122          /* Last hour with more than one hour */
03123          ||    ((cth > s1) &&
03124                 ((cth == e1) && (ctm <= e2)))
03125          )
03126             i->minmask[cth] |= (1 << (ctm / 2));
03127       }
03128    }
03129 #endif
03130    /* All done */
03131    return;
03132 }
03133 
03134 static char *days[] =
03135 {
03136    "sun",
03137    "mon",
03138    "tue",
03139    "wed",
03140    "thu",
03141    "fri",
03142    "sat",
03143 };
03144 
03145 static unsigned int get_dow(char *dow)
03146 {
03147    char *c;
03148    /* The following line is coincidence, really! */
03149    int s, e, x;
03150    unsigned int mask;
03151 
03152    /* Check for all days */
03153    if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
03154       return (1 << 7) - 1;
03155    /* Get start and ending days */
03156    c = strchr(dow, '-');
03157    if (c) {
03158       *c = '\0';
03159       c++;
03160    } else
03161       c = NULL;
03162    /* Find the start */
03163    s = 0;
03164    while((s < 7) && strcasecmp(dow, days[s])) s++;
03165    if (s >= 7) {
03166       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
03167       return 0;
03168    }
03169    if (c) {
03170       e = 0;
03171       while((e < 7) && strcasecmp(c, days[e])) e++;
03172       if (e >= 7) {
03173          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
03174          return 0;
03175       }
03176    } else
03177       e = s;
03178    mask = 0;
03179    for (x=s; x != e; x = (x + 1) % 7) {
03180       mask |= (1 << x);
03181    }
03182    /* One last one */
03183    mask |= (1 << x);
03184    return mask;
03185 }
03186 
03187 static unsigned int get_day(char *day)
03188 {
03189    char *c;
03190    /* The following line is coincidence, really! */
03191    int s, e, x;
03192    unsigned int mask;
03193 
03194    /* Check for all days */
03195    if (ast_strlen_zero(day) || !strcmp(day, "*")) {
03196       mask = (1 << 30)  + ((1 << 30) - 1);
03197       return mask;
03198    }
03199    /* Get start and ending days */
03200    c = strchr(day, '-');
03201    if (c) {
03202       *c = '\0';
03203       c++;
03204    }
03205    /* Find the start */
03206    if (sscanf(day, "%d", &s) != 1) {
03207       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
03208       return 0;
03209    }
03210    if ((s < 1) || (s > 31)) {
03211       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
03212       return 0;
03213    }
03214    s--;
03215    if (c) {
03216       if (sscanf(c, "%d", &e) != 1) {
03217          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
03218          return 0;
03219       }
03220       if ((e < 1) || (e > 31)) {
03221          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
03222          return 0;
03223       }
03224       e--;
03225    } else
03226       e = s;
03227    mask = 0;
03228    for (x=s;x!=e;x = (x + 1) % 31) {
03229       mask |= (1 << x);
03230    }
03231    mask |= (1 << x);
03232    return mask;
03233 }
03234 
03235 static char *months[] =
03236 {
03237    "jan",
03238    "feb",
03239    "mar",
03240    "apr",
03241    "may",
03242    "jun",
03243    "jul",
03244    "aug",
03245    "sep",
03246    "oct",
03247    "nov",
03248    "dec",
03249 };
03250 
03251 static unsigned int get_month(char *mon)
03252 {
03253    char *c;
03254    /* The following line is coincidence, really! */
03255    int s, e, x;
03256    unsigned int mask;
03257 
03258    /* Check for all days */
03259    if (ast_strlen_zero(mon) || !strcmp(mon, "*")) 
03260       return (1 << 12) - 1;
03261    /* Get start and ending days */
03262    c = strchr(mon, '-');
03263    if (c) {
03264       *c = '\0';
03265       c++;
03266    }
03267    /* Find the start */
03268    s = 0;
03269    while((s < 12) && strcasecmp(mon, months[s])) s++;
03270    if (s >= 12) {
03271       ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
03272       return 0;
03273    }
03274    if (c) {
03275       e = 0;
03276       while((e < 12) && strcasecmp(mon, months[e])) e++;
03277       if (e >= 12) {
03278          ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
03279          return 0;
03280       }
03281    } else
03282       e = s;
03283    mask = 0;
03284    for (x=s; x!=e; x = (x + 1) % 12) {
03285       mask |= (1 << x);
03286    }
03287    /* One last one */
03288    mask |= (1 << x);
03289    return mask;
03290 }
03291 
03292 static void build_timing(struct ast_include *i, char *info)
03293 {
03294    char *c;
03295 
03296    /* Check for empty just in case */
03297    if (ast_strlen_zero(info))
03298       return;
03299    i->hastime = 1;
03300    /* Assume everything except time */
03301    i->monthmask = (1 << 12) - 1;
03302    i->daymask = (1 << 30) - 1 + (1 << 30);
03303    i->dowmask = (1 << 7) - 1;
03304    /* Avoid using str tok */
03305    FIND_NEXT;
03306    /* Info has the time range, start with that */
03307    get_timerange(i, info);
03308    info = c;
03309    if (!info)
03310       return;
03311    FIND_NEXT;
03312    /* Now check for day of week */
03313    i->dowmask = get_dow(info);
03314 
03315    info = c;
03316    if (!info)
03317       return;
03318    FIND_NEXT;
03319    /* Now check for the day of the month */
03320    i->daymask = get_day(info);
03321    info = c;
03322    if (!info)
03323       return;
03324    FIND_NEXT;
03325    /* And finally go for the month */
03326    i->monthmask = get_month(info);
03327 }
03328 
03329 /*
03330  * errno values
03331  *  ENOMEM - out of memory
03332  *  EBUSY  - can't lock
03333  *  EEXIST - already included
03334  *  EINVAL - there is no existence of context for inclusion
03335  */
03336 int ast_context_add_include2(struct ast_context *con, char *value,
03337    char *registrar)
03338 {
03339    struct ast_include *new_include;
03340    char *c;
03341    struct ast_include *i, *il = NULL; /* include, include_last */
03342 
03343    /* allocate new include structure ... */
03344    if (!(new_include = malloc(sizeof(struct ast_include)))) {
03345       ast_log(LOG_ERROR, "Out of memory\n");
03346       errno = ENOMEM;
03347       return -1;
03348    }
03349    
03350    /* ... fill in this structure ... */
03351    memset(new_include, 0, sizeof(struct ast_include));
03352    strncpy(new_include->name, value, sizeof(new_include->name)-1);
03353    strncpy(new_include->rname, value, sizeof(new_include->rname)-1);
03354    c = new_include->rname;
03355    /* Strip off timing info */
03356    while(*c && (*c != '|')) c++; 
03357    /* Process if it's there */
03358    if (*c) {
03359       build_timing(new_include, c+1);
03360       *c = '\0';
03361    }
03362    new_include->next      = NULL;
03363    new_include->registrar = registrar;
03364 
03365    /* ... try to lock this context ... */
03366    if (ast_mutex_lock(&con->lock)) {
03367       free(new_include);
03368       errno = EBUSY;
03369       return -1;
03370    }
03371 
03372    /* ... go to last include and check if context is already included too... */
03373    i = con->includes;
03374    while (i) {
03375       if (!strcasecmp(i->name, new_include->name)) {
03376          free(new_include);
03377          ast_mutex_unlock(&con->lock);
03378          errno = EEXIST;
03379          return -1;
03380       }
03381       il = i;
03382       i = i->next;
03383    }
03384 
03385    /* ... include new context into context list, unlock, return */
03386    if (il)
03387       il->next = new_include;
03388    else
03389       con->includes = new_include;
03390    if (option_verbose > 2)
03391       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con)); 
03392    ast_mutex_unlock(&con->lock);
03393 
03394    return 0;
03395 }
03396 
03397 /*
03398  * errno values
03399  *  EBUSY  - can't lock
03400  *  ENOENT - no existence of context
03401  */
03402 int ast_context_add_switch(char *context, char *sw, char *data, char *registrar)
03403 {
03404    struct ast_context *c;
03405 
03406    if (ast_lock_contexts()) {
03407       errno = EBUSY;
03408       return -1;
03409    }
03410 
03411    /* walk contexts ... */
03412    c = ast_walk_contexts(NULL);
03413    while (c) {
03414       /* ... search for the right one ... */
03415       if (!strcmp(ast_get_context_name(c), context)) {
03416          int ret = ast_context_add_switch2(c, sw, data, registrar);
03417          /* ... unlock contexts list and return */
03418          ast_unlock_contexts();
03419          return ret;
03420       }
03421       c = ast_walk_contexts(c);
03422    }
03423 
03424    /* we can't find the right context */
03425    ast_unlock_contexts();
03426    errno = ENOENT;
03427    return -1;
03428 }
03429 
03430 /*
03431  * errno values
03432  *  ENOMEM - out of memory
03433  *  EBUSY  - can't lock
03434  *  EEXIST - already included
03435  *  EINVAL - there is no existence of context for inclusion
03436  */
03437 int ast_context_add_switch2(struct ast_context *con, char *value,
03438    char *data, char *registrar)
03439 {
03440    struct ast_sw *new_sw;
03441    struct ast_sw *i, *il = NULL; /* sw, sw_last */
03442 
03443    /* allocate new sw structure ... */
03444    if (!(new_sw = malloc(sizeof(struct ast_sw)))) {
03445       ast_log(LOG_ERROR, "Out of memory\n");
03446       errno = ENOMEM;
03447       return -1;
03448    }
03449    
03450    /* ... fill in this structure ... */
03451    memset(new_sw, 0, sizeof(struct ast_sw));
03452    strncpy(new_sw->name, value, sizeof(new_sw->name)-1);
03453    if (data)
03454       strncpy(new_sw->data, data, sizeof(new_sw->data)-1);
03455    else
03456       strncpy(new_sw->data, "", sizeof(new_sw->data)-1);
03457    new_sw->next      = NULL;
03458    new_sw->registrar = registrar;
03459 
03460    /* ... try to lock this context ... */
03461    if (ast_mutex_lock(&con->lock)) {
03462       free(new_sw);
03463       errno = EBUSY;
03464       return -1;
03465    }
03466 
03467    /* ... go to last sw and check if context is already swd too... */
03468    i = con->alts;
03469    while (i) {
03470       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
03471          free(new_sw);
03472          ast_mutex_unlock(&con->lock);
03473          errno = EEXIST;
03474          return -1;
03475       }
03476       il = i;
03477       i = i->next;
03478    }
03479 
03480    /* ... sw new context into context list, unlock, return */
03481    if (il)
03482       il->next = new_sw;
03483    else
03484       con->alts = new_sw;
03485    if (option_verbose > 2)
03486       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con)); 
03487    ast_mutex_unlock(&con->lock);
03488 
03489    return 0;
03490 }
03491 
03492 /*
03493  * EBUSY  - can't lock
03494  * ENOENT - there is not context existence
03495  */
03496 int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar)
03497 {
03498    struct ast_context *c;
03499 
03500    if (ast_lock_contexts()) {
03501       errno = EBUSY;
03502       return -1;
03503    }
03504 
03505    c = ast_walk_contexts(NULL);
03506    while (c) {
03507       if (!strcmp(ast_get_context_name(c), context)) {
03508          int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
03509          ast_unlock_contexts();
03510          return ret;
03511       }
03512       c = ast_walk_contexts(c);
03513    }
03514 
03515    ast_unlock_contexts();
03516    errno = ENOENT;
03517    return -1;
03518 }
03519 
03520 int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar)
03521 {
03522    struct ast_ignorepat *ip, *ipl = NULL;
03523 
03524    if (ast_mutex_lock(&con->lock)) {
03525       errno = EBUSY;
03526       return -1;
03527    }
03528 
03529    ip = con->ignorepats;
03530    while (ip) {
03531       if (!strcmp(ip->pattern, ignorepat) &&
03532          (!registrar || (registrar == ip->registrar))) {
03533          if (ipl) {
03534             ipl->next = ip->next;
03535             free(ip);
03536          } else {
03537             con->ignorepats = ip->next;
03538             free(ip);
03539          }
03540          ast_mutex_unlock(&con->lock);
03541          return 0;
03542       }
03543       ipl = ip; ip = ip->next;
03544    }
03545 
03546    ast_mutex_unlock(&con->lock);
03547    errno = EINVAL;
03548    return -1;
03549 }
03550 
03551 /*
03552  * EBUSY - can't lock
03553  * ENOENT - there is no existence of context
03554  */
03555 int ast_context_add_ignorepat(char *con, char *value, char *registrar)
03556 {
03557    struct ast_context *c;
03558 
03559    if (ast_lock_contexts()) {
03560       errno = EBUSY;
03561       return -1;
03562    }
03563 
03564    c = ast_walk_contexts(NULL);
03565    while (c) {
03566       if (!strcmp(ast_get_context_name(c), con)) {
03567          int ret = ast_context_add_ignorepat2(c, value, registrar);
03568          ast_unlock_contexts();
03569          return ret;
03570       } 
03571       c = ast_walk_contexts(c);
03572    }
03573 
03574    ast_unlock_contexts();
03575    errno = ENOENT;
03576    return -1;
03577 }
03578 
03579 int ast_context_add_ignorepat2(struct ast_context *con, char *value, char *registrar)
03580 {
03581    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
03582 
03583    ignorepat = malloc(sizeof(struct ast_ignorepat));
03584    if (!ignorepat) {
03585       ast_log(LOG_ERROR, "Out of memory\n");
03586       errno = ENOMEM;
03587       return -1;
03588    }
03589    memset(ignorepat, 0, sizeof(struct ast_ignorepat));
03590    strncpy(ignorepat->pattern, value, sizeof(ignorepat->pattern)-1);
03591    ignorepat->next = NULL;
03592    ignorepat->registrar = registrar;
03593    ast_mutex_lock(&con->lock);
03594    ignorepatc = con->ignorepats;
03595    while(ignorepatc) {
03596       ignorepatl = ignorepatc;
03597       if (!strcasecmp(ignorepatc->pattern, value)) {
03598          /* Already there */
03599          ast_mutex_unlock(&con->lock);
03600          errno = EEXIST;
03601          return -1;
03602       }
03603       ignorepatc = ignorepatc->next;
03604    }
03605    if (ignorepatl) 
03606       ignorepatl->next = ignorepat;
03607    else
03608       con->ignorepats = ignorepat;
03609    ast_mutex_unlock(&con->lock);
03610    return 0;
03611    
03612 }
03613 
03614 int ast_ignore_pattern(char *context, char *pattern)
03615 {
03616    struct ast_context *con;
03617    struct ast_ignorepat *pat;
03618 
03619    con = ast_context_find(context);
03620    if (con) {
03621       pat = con->ignorepats;
03622       while (pat) {
03623          if (ast_extension_match(pat->pattern, pattern))
03624             return 1;
03625          pat = pat->next;
03626       }
03627    } 
03628    return 0;
03629 }
03630 
03631 /*
03632  * EBUSY   - can't lock
03633  * ENOENT  - no existence of context
03634  *
03635  */
03636 int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
03637    char *application, void *data, void (*datad)(void *), char *registrar)
03638 {
03639    struct ast_context *c;
03640 
03641    if (ast_lock_contexts()) {
03642       errno = EBUSY;
03643       return -1;
03644    }
03645 
03646    c = ast_walk_contexts(NULL);
03647    while (c) {
03648       if (!strcmp(context, ast_get_context_name(c))) {
03649          int ret = ast_add_extension2(c, replace, extension, priority, callerid,
03650             application, data, datad, registrar);
03651          ast_unlock_contexts();
03652          return ret;
03653       }
03654       c = ast_walk_contexts(c);
03655    }
03656 
03657    ast_unlock_contexts();
03658    errno = ENOENT;
03659    return -1;
03660 }
03661 
03662 int ast_async_goto(struct ast_channel *chan, char *context, char *exten, int priority)
03663 {
03664    int res = 0;
03665    ast_mutex_lock(&chan->lock);
03666 
03667    if (chan->pbx) {
03668       /* This channel is currently in the PBX */
03669       if (context && !ast_strlen_zero(context))
03670          strncpy(chan->context, context, sizeof(chan->context) - 1);
03671       if (exten && !ast_strlen_zero(exten))
03672          strncpy(chan->exten, exten, sizeof(chan->context) - 1);
03673       if (priority)
03674          chan->priority = priority - 1;
03675       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
03676    } else {
03677       /* In order to do it when the channel doesn't really exist within
03678          the PBX, we have to make a new channel, masquerade, and start the PBX
03679          at the new location */
03680       struct ast_channel *tmpchan;
03681       tmpchan = ast_channel_alloc(0);
03682       if (tmpchan) {
03683          snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
03684          ast_setstate(tmpchan, chan->_state);
03685          /* Make formats okay */
03686          tmpchan->readformat = chan->readformat;
03687          tmpchan->writeformat = chan->writeformat;
03688          /* Setup proper location */
03689          if (context && !ast_strlen_zero(context))
03690             strncpy(tmpchan->context, context, sizeof(tmpchan->context) - 1);
03691          else
03692             strncpy(tmpchan->context, chan->context, sizeof(tmpchan->context) - 1);
03693          if (exten && !ast_strlen_zero(exten))
03694             strncpy(tmpchan->exten, exten, sizeof(tmpchan->exten) - 1);
03695          else
03696             strncpy(tmpchan->exten, chan->exten, sizeof(tmpchan->exten) - 1);
03697          if (priority)
03698             tmpchan->priority = priority;
03699          else
03700             tmpchan->priority = chan->priority;
03701          
03702          /* Masquerade into temp channel */
03703          ast_channel_masquerade(tmpchan, chan);
03704       
03705          /* Grab the locks and get going */
03706          ast_mutex_lock(&tmpchan->lock);
03707          ast_do_masquerade(tmpchan);
03708          ast_mutex_unlock(&tmpchan->lock);
03709          /* Start the PBX going on our stolen channel */
03710          if (ast_pbx_start(tmpchan)) {
03711             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
03712             ast_hangup(tmpchan);
03713             res = -1;
03714          }
03715       } else {
03716          res = -1;
03717       }
03718    }
03719    ast_mutex_unlock(&chan->lock);
03720    return res;
03721 }
03722 
03723 int ast_async_goto_by_name(char *channame, char *context, char *exten, int priority)
03724 {
03725    struct ast_channel *chan;
03726    int res = -1;
03727 
03728    chan = ast_channel_walk_locked(NULL);
03729    while(chan) {
03730       if (!strcasecmp(channame, chan->name))
03731          break;
03732       ast_mutex_unlock(&chan->lock);
03733       chan = ast_channel_walk_locked(chan);
03734    }
03735    
03736    if (chan) {
03737       res = ast_async_goto(chan, context, exten, priority);
03738       ast_mutex_unlock(&chan->lock);
03739    }
03740    return res;
03741 }
03742 
03743 static void ext_strncpy(char *dst, char *src, int len)
03744 {
03745    int count=0;
03746 
03747    while(*src && (count < len - 1)) {
03748       switch(*src) {
03749       case ' ':
03750          /* otherwise exten => [a-b],1,... doesn't work */
03751          /*    case '-': */
03752          /* Ignore */
03753          break;
03754       default:
03755          *dst = *src;
03756          dst++;
03757       }
03758       src++;
03759       count++;
03760    }
03761    *dst = '\0';
03762 }
03763 
03764 /*
03765  * EBUSY - can't lock
03766  * EEXIST - extension with the same priority exist and no replace is set
03767  *
03768  */
03769 int ast_add_extension2(struct ast_context *con,
03770                  int replace, char *extension, int priority, char *callerid,
03771                  char *application, void *data, void (*datad)(void *),
03772                  char *registrar)
03773 {
03774 
03775 #define LOG do {  if (option_debug) {\
03776       if (tmp->matchcid) { \
03777          ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
03778       } else { \
03779          ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
03780       } \
03781    } else if (option_verbose > 2) { \
03782       if (tmp->matchcid) { \
03783          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
03784       } else {  \
03785          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
03786       } \
03787    } } while(0)
03788 
03789    /*
03790     * This is a fairly complex routine.  Different extensions are kept
03791     * in order by the extension number.  Then, extensions of different
03792     * priorities (same extension) are kept in a list, according to the
03793     * peer pointer.
03794     */
03795    struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
03796    int res;
03797 
03798    /* Be optimistic:  Build the extension structure first */
03799    tmp = malloc(sizeof(struct ast_exten));
03800    if (tmp) {
03801       memset(tmp, 0, sizeof(struct ast_exten));
03802       ext_strncpy(tmp->exten, extension, sizeof(tmp->exten));
03803       tmp->priority = priority;
03804       if (callerid) {
03805          ext_strncpy(tmp->cidmatch, callerid, sizeof(tmp->cidmatch));
03806          tmp->matchcid = 1;
03807       } else {
03808          tmp->cidmatch[0] = '\0';
03809          tmp->matchcid = 0;
03810       }
03811       strncpy(tmp->app, application, sizeof(tmp->app)-1);
03812       tmp->parent = con;
03813       tmp->data = data;
03814       tmp->datad = datad;
03815       tmp->registrar = registrar;
03816       tmp->peer = NULL;
03817       tmp->next =  NULL;
03818    } else {
03819       ast_log(LOG_ERROR, "Out of memory\n");
03820       errno = ENOMEM;
03821       return -1;
03822    }
03823    if (ast_mutex_lock(&con->lock)) {
03824       free(tmp);
03825       /* And properly destroy the data */
03826       datad(data);
03827       ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
03828       errno = EBUSY;
03829       return -1;
03830    }
03831    e = con->root;
03832    while(e) {
03833       /* Make sure patterns are always last! */
03834       if ((e->exten[0] != '_') && (extension[0] == '_'))
03835          res = -1;
03836       else if ((e->exten[0] == '_') && (extension[0] != '_'))
03837          res = 1;
03838       else
03839          res= strcmp(e->exten, extension);
03840       if (!res) {
03841          if (!e->matchcid && !tmp->matchcid)
03842             res = 0;
03843          else if (tmp->matchcid && !e->matchcid)
03844             res = 1;
03845          else if (e->matchcid && !tmp->matchcid)
03846             res = -1;
03847          else
03848             res = strcasecmp(e->cidmatch, tmp->cidmatch);
03849       }
03850       if (res == 0) {
03851          /* We have an exact match, now we find where we are
03852             and be sure there's no duplicates */
03853          while(e) {
03854             if (e->priority == tmp->priority) {
03855                /* Can't have something exactly the same.  Is this a
03856                   replacement?  If so, replace, otherwise, bonk. */
03857                if (replace) {
03858                   if (ep) {
03859                      /* We're in the peer list, insert ourselves */
03860                      ep->peer = tmp;
03861                      tmp->peer = e->peer;
03862                   } else if (el) {
03863                      /* We're the first extension. Take over e's functions */
03864                      el->next = tmp;
03865                      tmp->next = e->next;
03866                      tmp->peer = e->peer;
03867                   } else {
03868                      /* We're the very first extension.  */
03869                      con->root = tmp;
03870                      tmp->next = e->next;
03871                      tmp->peer = e->peer;
03872                   }
03873                   if (tmp->priority == PRIORITY_HINT)
03874                       ast_change_hint(e,tmp);
03875                   /* Destroy the old one */
03876                   e->datad(e->data);
03877                   free(e);
03878                   ast_mutex_unlock(&con->lock);
03879                   if (tmp->priority == PRIORITY_HINT)
03880                       ast_change_hint(e, tmp);
03881                   /* And immediately return success. */
03882                   LOG;
03883                   return 0;
03884                } else {
03885                   ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
03886                   tmp->datad(tmp->data);
03887                   free(tmp);
03888                   ast_mutex_unlock(&con->lock);
03889                   errno = EEXIST;
03890                   return -1;
03891                }
03892             } else if (e->priority > tmp->priority) {
03893                /* Slip ourselves in just before e */
03894                if (ep) {
03895                   /* Easy enough, we're just in the peer list */
03896                   ep->peer = tmp;
03897                   tmp->peer = e;
03898                } else if (el) {
03899                   /* We're the first extension in this peer list */
03900                   el->next = tmp;
03901                   tmp->next = e->next;
03902                   e->next = NULL;
03903                   tmp->peer = e;
03904                } else {
03905                   /* We're the very first extension altogether */
03906                   tmp->next = con->root->next;
03907                   /* Con->root must always exist or we couldn't get here */
03908                   tmp->peer = con->root;
03909                   con->root = tmp;
03910                }
03911                ast_mutex_unlock(&con->lock);
03912                /* And immediately return success. */
03913                if (tmp->priority == PRIORITY_HINT)
03914                    ast_add_hint(tmp);
03915                
03916                LOG;
03917                return 0;
03918             }
03919             ep = e;
03920             e = e->peer;
03921          }
03922          /* If we make it here, then it's time for us to go at the very end.
03923             ep *must* be defined or we couldn't have gotten here. */
03924          ep->peer = tmp;
03925          ast_mutex_unlock(&con->lock);
03926          if (tmp->priority == PRIORITY_HINT)
03927             ast_add_hint(tmp);
03928          
03929          /* And immediately return success. */
03930          LOG;
03931          return 0;
03932             
03933       } else if (res > 0) {
03934          /* Insert ourselves just before 'e'.  We're the first extension of
03935             this kind */
03936          tmp->next = e;
03937          if (el) {
03938             /* We're in the list somewhere */
03939             el->next = tmp;
03940          } else {
03941             /* We're at the top of the list */
03942             con->root = tmp;
03943          }
03944          ast_mutex_unlock(&con->lock);
03945          if (tmp->priority == PRIORITY_HINT)
03946             ast_add_hint(tmp);
03947 
03948          /* And immediately return success. */
03949          LOG;
03950          return 0;
03951       }        
03952          
03953       el = e;
03954       e = e->next;
03955    }
03956    /* If we fall all the way through to here, then we need to be on the end. */
03957    if (el)
03958       el->next = tmp;
03959    else
03960       con->root = tmp;
03961    ast_mutex_unlock(&con->lock);
03962    if (tmp->priority == PRIORITY_HINT)
03963       ast_add_hint(tmp);
03964    LOG;
03965    return 0;   
03966 }
03967 
03968 struct async_stat {
03969    pthread_t p;
03970    struct ast_channel *chan;
03971    char context[AST_MAX_EXTENSION];
03972    char exten[AST_MAX_EXTENSION];
03973    int priority;
03974    int timeout;
03975    char app[AST_MAX_EXTENSION];
03976    char appdata[1024];
03977 };
03978 
03979 static void *async_wait(void *data) 
03980 {
03981    struct async_stat *as = data;
03982    struct ast_channel *chan = as->chan;
03983    int timeout = as->timeout;
03984    int res;
03985    struct ast_frame *f;
03986    struct ast_app *app;
03987    
03988    while(timeout && (chan->_state != AST_STATE_UP)) {
03989       res = ast_waitfor(chan, timeout);
03990       if (res < 1) 
03991          break;
03992       if (timeout > -1)
03993          timeout = res;
03994       f = ast_read(chan);
03995       if (!f)
03996          break;
03997       if (f->frametype == AST_FRAME_CONTROL) {
03998          if ((f->subclass == AST_CONTROL_BUSY)  ||
03999             (f->subclass == AST_CONTROL_CONGESTION) )
04000                break;
04001       }
04002       ast_frfree(f);
04003    }
04004    if (chan->_state == AST_STATE_UP) {
04005       if (!ast_strlen_zero(as->app)) {
04006          app = pbx_findapp(as->app);
04007          if (app) {
04008             if (option_verbose > 2)
04009                ast_verbose(VERBOSE_PREFIX_3 "Lauching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04010             pbx_exec(chan, app, as->appdata, 1);
04011          } else
04012             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04013       } else {
04014          if (!ast_strlen_zero(as->context))
04015             strncpy(chan->context, as->context, sizeof(chan->context) - 1);
04016          if (!ast_strlen_zero(as->exten))
04017             strncpy(chan->exten, as->exten, sizeof(chan->exten) - 1);
04018          if (as->priority > 0)
04019             chan->priority = as->priority;
04020          /* Run the PBX */
04021          if (ast_pbx_run(chan)) {
04022             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04023          } else {
04024             /* PBX will have taken care of this */
04025             chan = NULL;
04026          }
04027       }
04028          
04029    }
04030    free(as);
04031    if (chan)
04032       ast_hangup(chan);
04033    return NULL;
04034 }
04035 
04036 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)
04037 {
04038    struct ast_channel *chan;
04039    struct async_stat *as;
04040    int res = -1;
04041    char *var, *tmp;
04042    struct outgoing_helper oh;
04043    pthread_attr_t attr;
04044       
04045    if (sync) {
04046       LOAD_OH(oh);
04047       chan = __ast_request_and_dial(type, format, data, timeout, reason, callerid, &oh);
04048       if (chan) {
04049          pbx_builtin_setaccount(chan, account);
04050          if (chan->_state == AST_STATE_UP) {
04051                res = 0;
04052             if (option_verbose > 3)
04053                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
04054 
04055             if (sync > 1) {
04056                if (ast_pbx_run(chan)) {
04057                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
04058                   ast_hangup(chan);
04059                   res = -1;
04060                }
04061             } else {
04062                if (ast_pbx_start(chan)) {
04063                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
04064                   ast_hangup(chan);
04065                   res = -1;
04066                } 
04067             }
04068          } else {
04069             if (option_verbose > 3)
04070                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
04071             ast_hangup(chan);
04072          }
04073       }
04074 
04075       if(res < 0) { /* the call failed for some reason */
04076          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
04077          /* check if "failed" exists */
04078          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
04079             chan = ast_channel_alloc(0);
04080             if (chan) {
04081                strncpy(chan->name, "OutgoingSpoolFailed", sizeof(chan->name) - 1);
04082                if (context && !ast_strlen_zero(context))
04083                   strncpy(chan->context, context, sizeof(chan->context) - 1);
04084                strncpy(chan->exten, "failed", sizeof(chan->exten) - 1);
04085                chan->priority = 1;
04086                if (variable) {
04087                   tmp = ast_strdupa(variable);
04088                   for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp)) {
04089                      pbx_builtin_setvar( chan, var );
04090                   }
04091                }
04092                ast_pbx_run(chan);   
04093             } else
04094                ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
04095          }
04096       }
04097    } else {
04098       as = malloc(sizeof(struct async_stat));
04099       if (!as)
04100          return -1;
04101       memset(as, 0, sizeof(struct async_stat));
04102       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
04103       if (!chan) {
04104          free(as);
04105          return -1;
04106       }
04107       pbx_builtin_setaccount(chan, account);
04108       as->chan = chan;
04109       strncpy(as->context, context, sizeof(as->context) - 1);
04110       strncpy(as->exten,  exten, sizeof(as->exten) - 1);
04111       as->priority = priority;
04112       as->timeout = timeout;
04113       if (variable) {
04114          tmp = ast_strdupa(variable);
04115          for (var = strtok_r(tmp, "|", &tmp); var; var = strtok_r(NULL, "|", &tmp))
04116             pbx_builtin_setvar( chan, var );
04117       }
04118       pthread_attr_init(&attr);
04119       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04120       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
04121          ast_log(LOG_WARNING, "Failed to start async wait\n");
04122          free(as);
04123          ast_hangup(chan);
04124          return -1;
04125       }
04126       res = 0;
04127    }
04128    return res;
04129 }
04130 
04131 struct app_tmp {
04132    char app[256];
04133    char data[256];
04134    struct ast_channel *chan;
04135    pthread_t t;
04136 };
04137 
04138 static void *ast_pbx_run_app(void *data)
04139 {
04140    struct app_tmp *tmp = data;
04141    struct ast_app *app;
04142    app = pbx_findapp(tmp->app);
04143    if (app) {
04144       if (option_verbose > 3)
04145          ast_verbose(VERBOSE_PREFIX_4 "Lauching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
04146       pbx_exec(tmp->chan, app, tmp->data, 1);
04147    } else
04148       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
04149    ast_hangup(tmp->chan);
04150    free(tmp);
04151    return NULL;
04152 }
04153 
04154 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)
04155 {
04156    struct ast_channel *chan;
04157    struct async_stat *as;
04158    struct app_tmp *tmp;
04159    char *var, *vartmp;
04160    int res = -1;
04161    pthread_attr_t attr;
04162    
04163    if (!app || ast_strlen_zero(app))
04164       return -1;
04165    if (sync) {
04166       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
04167       if (chan) {
04168          pbx_builtin_setaccount(chan, account);
04169          if (variable) {
04170             vartmp = ast_strdupa(variable);
04171             for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp)) {
04172                pbx_builtin_setvar( chan, var );
04173             }
04174          }
04175          if (chan->_state == AST_STATE_UP) {
04176             res = 0;
04177             if (option_verbose > 3)
04178                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
04179             tmp = malloc(sizeof(struct app_tmp));
04180             if (tmp) {
04181                memset(tmp, 0, sizeof(struct app_tmp));
04182                strncpy(tmp->app, app, sizeof(tmp->app) - 1);
04183                strncpy(tmp->data, appdata, sizeof(tmp->data) - 1);
04184                tmp->chan = chan;
04185                if (sync > 1) {
04186                   ast_pbx_run_app(tmp);
04187                } else {
04188                   pthread_attr_init(&attr);
04189                   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04190                   if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
04191                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
04192                      free(tmp);
04193                      ast_hangup(chan);
04194                      res = -1;
04195                   }
04196                }
04197             } else {
04198                ast_log(LOG_ERROR, "Out of memory :(\n");
04199                res = -1;
04200             }
04201          } else {
04202             if (option_verbose > 3)
04203                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
04204             ast_hangup(chan);
04205          }
04206       }
04207    } else {
04208       as = malloc(sizeof(struct async_stat));
04209       if (!as)
04210          return -1;
04211       memset(as, 0, sizeof(struct async_stat));
04212       chan = ast_request_and_dial(type, format, data, timeout, reason, callerid);
04213       if (!chan) {
04214          free(as);
04215          return -1;
04216       }
04217       pbx_builtin_setaccount(chan, account);
04218       as->chan = chan;
04219       strncpy(as->app, app, sizeof(as->app) - 1);
04220       if (appdata)
04221          strncpy(as->appdata,  appdata, sizeof(as->appdata) - 1);
04222       as->timeout = timeout;
04223       if (variable) {
04224          vartmp = ast_strdupa(variable);
04225          for (var = strtok_r(vartmp, "|", &vartmp); var; var = strtok_r(NULL, "|", &vartmp))
04226             pbx_builtin_setvar( chan, var );
04227       }
04228       /* Start a new thread, and get something handling this channel. */
04229       pthread_attr_init(&attr);
04230       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04231       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
04232          ast_log(LOG_WARNING, "Failed to start async wait\n");
04233          free(as);
04234          ast_hangup(chan);
04235          return -1;
04236       }
04237       res = 0;
04238    }
04239    return res;
04240 }
04241 
04242 static void destroy_exten(struct ast_exten *e)
04243 {
04244    if (e->priority == PRIORITY_HINT)
04245       ast_remove_hint(e);
04246 
04247    if (e->datad)
04248       e->datad(e->data);
04249    free(e);
04250 }
04251 
04252 void __ast_context_destroy(struct ast_context *con, char *registrar)
04253 {
04254    struct ast_context *tmp, *tmpl=NULL;
04255    struct ast_include *tmpi, *tmpil= NULL;
04256    struct ast_sw *sw, *swl= NULL;
04257    struct ast_exten *e, *el, *en;
04258    struct ast_ignorepat *ipi, *ipl = NULL;
04259 
04260    ast_mutex_lock(&conlock);
04261    tmp = contexts;
04262    while(tmp) {
04263       if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
04264           (!registrar || !strcasecmp(registrar, tmp->registrar))) {
04265          /* Okay, let's lock the structure to be sure nobody else
04266             is searching through it. */
04267          if (ast_mutex_lock(&tmp->lock)) {
04268             ast_log(LOG_WARNING, "Unable to lock context lock\n");
04269             return;
04270          }
04271          if (tmpl)
04272             tmpl->next = tmp->next;
04273          else
04274             contexts = tmp->next;
04275          /* Okay, now we're safe to let it go -- in a sense, we were
04276             ready to let it go as soon as we locked it. */
04277          ast_mutex_unlock(&tmp->lock);
04278          for (tmpi = tmp->includes; tmpi; ) {
04279             /* Free includes */
04280             tmpil = tmpi;
04281             tmpi = tmpi->next;
04282             free(tmpil);
04283          }
04284          for (ipi = tmp->ignorepats; ipi; ) {
04285             /* Free ignorepats */
04286             ipl = ipi;
04287             ipi = ipi->next;
04288             free(ipl);
04289          }
04290          for (sw = tmp->alts; sw; ) {
04291             /* Free switches */
04292             swl = sw;
04293             sw = sw->next;
04294             free(swl);
04295             swl = sw;
04296          }
04297          for (e = tmp->root; e;) {
04298             for (en = e->peer; en;) {
04299                el = en;
04300                en = en->peer;
04301                destroy_exten(el);
04302             }
04303             el = e;
04304             e = e->next;
04305             destroy_exten(el);
04306          }
04307                         ast_mutex_destroy(&tmp->lock);
04308          free(tmp);
04309          if (!con) {
04310             /* Might need to get another one -- restart */
04311             tmp = contexts;
04312             tmpl = NULL;
04313             tmpil = NULL;
04314             continue;
04315          }
04316          ast_mutex_unlock(&conlock);
04317          return;
04318       }
04319       tmpl = tmp;
04320       tmp = tmp->next;
04321    }
04322    ast_mutex_unlock(&conlock);
04323 }
04324 
04325 void ast_context_destroy(struct ast_context *con, char *registrar)
04326 {
04327    __ast_context_destroy(con,registrar);
04328 }
04329 
04330 static void wait_for_hangup(struct ast_channel *chan, void *data)
04331 {
04332    int res;
04333    struct ast_frame *f;
04334    int waittime;
04335    
04336    if (!data || !strlen(data) || (sscanf(data, "%i", &waittime) != 1) || (waittime < 0))
04337       waittime = -1;
04338    if (waittime > -1) {
04339       ast_safe_sleep(chan, waittime * 1000);
04340    } else do {
04341       res = ast_waitfor(chan, -1);
04342       if (res < 0)
04343          return;
04344       f = ast_read(chan);
04345       if (f)
04346          ast_frfree(f);
04347    } while(f);
04348 }
04349 
04350 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
04351 {
04352    ast_indicate(chan, AST_CONTROL_PROGRESS);
04353    return 0;
04354 }
04355 
04356 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
04357 {
04358    ast_indicate(chan, AST_CONTROL_RINGING);
04359    return 0;
04360 }
04361 
04362 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
04363 {
04364    ast_indicate(chan, AST_CONTROL_BUSY);     
04365    wait_for_hangup(chan, data);
04366    return -1;
04367 }
04368 
04369 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
04370 {
04371    ast_indicate(chan, AST_CONTROL_CONGESTION);
04372    wait_for_hangup(chan, data);
04373    return -1;
04374 }
04375 
04376 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
04377 {
04378    return ast_answer(chan);
04379 }
04380 
04381 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
04382 {
04383    /* Copy the language as specified */
04384    strncpy(chan->language, (char *)data, sizeof(chan->language)-1);
04385    return 0;
04386 }
04387 
04388 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
04389 {
04390    int flags = 0;
04391    /* Reset the CDR as specified */
04392    if(data) {
04393       if(strchr((char *)data, 'w'))
04394          flags |= AST_CDR_FLAG_POSTED;
04395       if(strchr((char *)data, 'a'))
04396          flags |= AST_CDR_FLAG_LOCKED;
04397    }
04398 
04399    ast_cdr_reset(chan->cdr, flags);
04400    return 0;
04401 }
04402 
04403 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
04404 {
04405    /* Copy the account code  as specified */
04406    if (data)
04407       ast_cdr_setaccount(chan, (char *)data);
04408    else
04409       ast_cdr_setaccount(chan, "");
04410    return 0;
04411 }
04412 
04413 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
04414 {
04415    /* Copy the AMA Flags as specified */
04416    if (data)
04417       ast_cdr_setamaflags(chan, (char *)data);
04418    else
04419       ast_cdr_setamaflags(chan, "");
04420    return 0;
04421 }
04422 
04423 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
04424 {
04425    /* Just return non-zero and it will hang up */
04426    return -1;
04427 }
04428 
04429 static int pbx_builtin_stripmsd(struct ast_channel *chan, void *data)
04430 {
04431    char newexten[AST_MAX_EXTENSION] = "";
04432 
04433    if (!data || !atoi(data)) {
04434       ast_log(LOG_DEBUG, "Ignoring, since number of digits to strip is 0\n");
04435       return 0;
04436    }
04437    if (strlen(chan->exten) > atoi(data)) {
04438       strncpy(newexten, chan->exten + atoi(data), sizeof(newexten)-1);
04439    }
04440    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04441    return 0;
04442 }
04443 
04444 static int pbx_builtin_prefix(struct ast_channel *chan, void *data)
04445 {
04446    char newexten[AST_MAX_EXTENSION] = "";
04447 
04448    if (!data || ast_strlen_zero(data)) {
04449       ast_log(LOG_DEBUG, "Ignoring, since there is no prefix to add\n");
04450       return 0;
04451    }
04452    snprintf(newexten, sizeof(newexten), "%s%s", (char *)data, chan->exten);
04453    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04454    if (option_verbose > 2)
04455       ast_verbose(VERBOSE_PREFIX_3 "Prepended prefix, new extension is %s\n", chan->exten);
04456    return 0;
04457 }
04458 
04459 static int pbx_builtin_suffix(struct ast_channel *chan, void *data)
04460 {
04461    char newexten[AST_MAX_EXTENSION] = "";
04462 
04463    if (!data || ast_strlen_zero(data)) {
04464       ast_log(LOG_DEBUG, "Ignoring, since there is no suffix to add\n");
04465       return 0;
04466    }
04467    snprintf(newexten, sizeof(newexten), "%s%s", chan->exten, (char *)data);
04468    strncpy(chan->exten, newexten, sizeof(chan->exten)-1);
04469    if (option_verbose > 2)
04470       ast_verbose(VERBOSE_PREFIX_3 "Appended suffix, new extension is %s\n", chan->exten);
04471    return 0;
04472 }
04473 
04474 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
04475 {
04476    int res=0;
04477    char *s, *ts;
04478    struct ast_include include;
04479 
04480    if (!data) {
04481       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
04482       return -1;
04483    }
04484 
04485    s = strdup((char *) data);
04486    ts = s;
04487 
04488    /* Separate the Goto path */
04489    strsep(&ts,"?");
04490 
04491    /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
04492    build_timing(&include, s);
04493    if (include_valid(&include))
04494       res = pbx_builtin_goto(chan, (void *)ts);
04495    free(s);
04496    return res;
04497 }
04498 
04499 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
04500 {
04501    int ms;
04502 
04503    /* Wait for "n" seconds */
04504    if (data && atof((char *)data)) {
04505       ms = atof((char *)data) * 1000;
04506       return ast_safe_sleep(chan, ms);
04507    }
04508    return 0;
04509 }
04510 
04511 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
04512 {
04513    int ms;
04514 
04515    /* Wait for "n" seconds */
04516    if (data && atof((char *)data)) {
04517       ms = atof((char *)data) * 1000;
04518       return ast_waitfordigit(chan, ms);
04519    }
04520    return 0;
04521 }
04522 
04523 static int pbx_builtin_background(struct ast_channel *chan, void *data)
04524 {
04525    int res = 0;
04526    int option_skip = 0;
04527    int option_noanswer = 0;
04528    char filename[256] = "";
04529    char* stringp;
04530    char* options;
04531    char *lang = NULL;
04532 
04533    if (!data || ast_strlen_zero(data)) {
04534       ast_log(LOG_WARNING, "Background requires an argument(filename)\n");
04535       return -1;
04536    }
04537 
04538    strncpy(filename, (char*)data, sizeof(filename) - 1);
04539    stringp = filename;
04540    strsep(&stringp, "|");
04541    options = strsep(&stringp, "|");
04542    if (options)
04543       lang = strsep(&stringp, "|");
04544    if (!lang)
04545       lang = chan->language;
04546 
04547    if (options && !strcasecmp(options, "skip"))
04548       option_skip = 1;
04549    if (options && !strcasecmp(options, "noanswer"))
04550       option_noanswer = 1;
04551 
04552    /* Answer if need be */
04553    if (chan->_state != AST_STATE_UP) {
04554       if (option_skip) {
04555          return 0;
04556       } else if (!option_noanswer) {
04557          res = ast_answer(chan);
04558       }
04559    }
04560 
04561    if (!res) {
04562       /* Stop anything playing */
04563       ast_stopstream(chan);
04564       /* Stream a file */
04565       res = ast_streamfile(chan, filename, lang);
04566       if (!res) {
04567          res = ast_waitstream(chan, AST_DIGIT_ANY);
04568          ast_stopstream(chan);
04569       } else {
04570          ast_log(LOG_WARNING, "ast_streamfile failed on %s fro %s\n", chan->name, (char*)data);
04571          res = 0;
04572       }
04573    }
04574 
04575    return res;
04576 }
04577 
04578 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
04579 {
04580    int x = atoi((char *) data);
04581 
04582    /* Set the absolute maximum time how long a call can be connected */
04583    ast_channel_setwhentohangup(chan,x);
04584    if (option_verbose > 2)
04585       ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
04586    return 0;
04587 }
04588 
04589 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
04590 {
04591    /* Set the timeout for how long to wait between digits */
04592    chan->pbx->rtimeout = atoi((char *)data);
04593    if (option_verbose > 2)
04594       ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
04595    return 0;
04596 }
04597 
04598 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
04599 {
04600    /* Set the timeout for how long to wait between digits */
04601    chan->pbx->dtimeout = atoi((char *)data);
04602    if (option_verbose > 2)
04603       ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
04604    return 0;
04605 }
04606 
04607 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
04608 {
04609    char *s;
04610    char *exten, *pri, *context;
04611    char *stringp=NULL;
04612 
04613    if (!data || ast_strlen_zero(data)) {
04614       ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
04615       return -1;
04616    }
04617    s = ast_strdupa((void *) data);
04618    stringp=s;
04619    context = strsep(&stringp, "|");
04620    exten = strsep(&stringp, "|");
04621    if (!exten) {
04622       /* Only a priority in this one */
04623       pri = context;
04624       exten = NULL;
04625       context = NULL;
04626    } else {
04627       pri = strsep(&stringp, "|");
04628       if (!pri) {
04629          /* Only an extension and priority in this one */
04630          pri = exten;
04631          exten = context;
04632          context = NULL;
04633       }
04634    }
04635    if (atoi(pri) < 0) {
04636       ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", pri);
04637       return -1;
04638    }
04639    /* At this point we have a priority and maybe an extension and a context */
04640    chan->priority = atoi(pri) - 1;
04641    if (exten && strcasecmp(exten, "BYEXTENSION"))
04642       strncpy(chan->exten, exten, sizeof(chan->exten)-1);
04643    if (context)
04644       strncpy(chan->context, context, sizeof(chan->context)-1);
04645    if (option_verbose > 2)
04646       ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
04647    ast_cdr_update(chan);
04648    return 0;
04649 }
04650 
04651 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name) 
04652 {
04653    struct ast_var_t *variables;
04654    struct varshead *headp;
04655 
04656    if (chan)
04657       headp=&chan->varshead;
04658    else
04659       headp=&globals;
04660 
04661    if (name) {
04662       AST_LIST_TRAVERSE(headp,variables,entries) {
04663          if (!strcmp(name, ast_var_name(variables)))
04664             return ast_var_value(variables);
04665       }
04666       if (headp != &globals) {
04667          /* Check global variables if we haven't already */
04668          headp = &globals;
04669          AST_LIST_TRAVERSE(headp,variables,entries) {
04670             if (!strcmp(name, ast_var_name(variables)))
04671                return ast_var_value(variables);
04672          }
04673       }
04674    }
04675    return NULL;
04676 }
04677 
04678 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value) 
04679 {
04680    struct ast_var_t *newvariable;
04681    struct varshead *headp;
04682    if (chan)
04683       headp=&chan->varshead;
04684    else
04685       headp=&globals;
04686                 
04687    AST_LIST_TRAVERSE (headp,newvariable,entries) {
04688       if (strcasecmp(ast_var_name(newvariable),name)==0) {
04689          /* there is already such a variable, delete it */
04690          AST_LIST_REMOVE(headp,newvariable,ast_var_t,entries);
04691          ast_var_delete(newvariable);
04692          break;
04693       }
04694    } 
04695    
04696    if (value) {
04697       if ((option_verbose > 1) && (headp == &globals))
04698          ast_verbose(VERBOSE_PREFIX_3 "Setting global variable '%s' to '%s'\n",name, value);
04699       newvariable=ast_var_assign(name,value);   
04700       AST_LIST_INSERT_HEAD(headp,newvariable,entries);
04701    }
04702 }
04703 
04704 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
04705 {
04706    char *name;
04707    char *value;
04708    char *stringp=NULL;
04709                 
04710    if (!data || ast_strlen_zero(data)) {
04711       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04712       return 0;
04713    }
04714    
04715    stringp=data;
04716    name=strsep(&stringp,"=");
04717    value=strsep(&stringp,"\0"); 
04718    
04719    pbx_builtin_setvar_helper(chan,name,value);
04720          
04721         return(0);
04722 }
04723 
04724 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
04725 {
04726    char *name;
04727    char *value;
04728    char *stringp=NULL;
04729                 
04730    if (!data || ast_strlen_zero(data)) {
04731       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
04732       return 0;
04733    }
04734    
04735    stringp=data;
04736    name=strsep(&stringp,"=");
04737    value=strsep(&stringp,"\0"); 
04738    
04739    pbx_builtin_setvar_helper(NULL,name,value);
04740          
04741         return(0);
04742 }
04743 
04744 
04745 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
04746 {
04747    return 0;
04748 }
04749 
04750 
04751 void pbx_builtin_clear_globals(void)
04752 {
04753    struct ast_var_t *vardata;
04754    while (!AST_LIST_EMPTY(&globals)) {
04755       vardata = AST_LIST_FIRST(&globals);
04756       AST_LIST_REMOVE_HEAD(&globals, entries);
04757       ast_var_delete(vardata);
04758    }
04759 }
04760 
04761 static int pbx_checkcondition(char *condition) 
04762 {
04763    return condition ? atoi(condition) : 0;
04764 }
04765 
04766 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
04767 {
04768    char *condition,*branch1,*branch2,*branch;
04769    char *s;
04770    int rc;
04771    char *stringp=NULL;
04772 
04773    if (!data || ast_strlen_zero(data)) {
04774       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
04775       return 0;
04776    }
04777    
04778    s=ast_strdupa(data);
04779    stringp=s;
04780    condition=strsep(&stringp,"?");
04781    branch1=strsep(&stringp,":");
04782    branch2=strsep(&stringp,"");
04783    branch = pbx_checkcondition(condition) ? branch1 : branch2;
04784    
04785    if ((branch==NULL) || ast_strlen_zero(branch)) {
04786       ast_log(LOG_DEBUG, "Not taking any branch\n");
04787       return(0);
04788    }
04789    
04790    rc=pbx_builtin_goto(chan,branch);
04791 
04792    return(rc);
04793 }           
04794 
04795 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
04796 {
04797    int res = 0;
04798    char tmp[256];
04799    char *number = (char *) NULL;
04800    char *options = (char *) NULL;
04801 
04802    
04803    if (!data || ast_strlen_zero((char *)data)) {
04804                 ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
04805                 return -1;
04806         }
04807         strncpy(tmp, (char *)data, sizeof(tmp)-1);
04808         number=tmp;
04809         strsep(&number, "|");
04810         options = strsep(&number, "|");
04811         if (options) { 
04812       if ( strcasecmp(options, "f") && strcasecmp(options,"m") && 
04813          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
04814                    ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
04815                    return -1;
04816       }
04817    }
04818    return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
04819 }
04820 
04821 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
04822 {
04823    int res = 0;
04824 
04825    if (data)
04826       res = ast_say_digit_str(chan, (char *)data, "", chan->language);
04827    return res;
04828 }
04829    
04830 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
04831 {
04832    int res = 0;
04833 
04834    if (data)
04835       res = ast_say_character_str(chan, (char *)data, "", chan->language);
04836    return res;
04837 }
04838    
04839 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
04840 {
04841    int res = 0;
04842 
04843    if (data)
04844       res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
04845    return res;
04846 }
04847    
04848 int load_pbx(void)
04849 {
04850    int x;
04851 
04852    /* Initialize the PBX */
04853    if (option_verbose) {
04854       ast_verbose( "Asterisk PBX Core Initializing\n");
04855       ast_verbose( "Registering builtin applications:\n");
04856    }
04857         AST_LIST_HEAD_INIT(&globals);
04858    ast_cli_register(&show_applications_cli);
04859    ast_cli_register(&show_application_cli);
04860    ast_cli_register(&show_dialplan_cli);
04861    ast_cli_register(&show_switches_cli);
04862 
04863    /* Register builtin applications */
04864    for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
04865       if (option_verbose)
04866          ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
04867       if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
04868          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
04869          return -1;
04870       }
04871    }
04872    return 0;
04873 }
04874 
04875 /*
04876  * Lock context list functions ...
04877  */
04878 int ast_lock_contexts()
04879 {
04880    return ast_mutex_lock(&conlock);
04881 }
04882 
04883 int ast_unlock_contexts()
04884 {
04885    return ast_mutex_unlock(&conlock);
04886 }
04887 
04888 /*
04889  * Lock context ...
04890  */
04891 int ast_lock_context(struct ast_context *con)
04892 {
04893    return ast_mutex_lock(&con->lock);
04894 }
04895 
04896 int ast_unlock_context(struct ast_context *con)
04897 {
04898    return ast_mutex_unlock(&con->lock);
04899 }
04900 
04901 /*
04902  * Name functions ...
04903  */
04904 char *ast_get_context_name(struct ast_context *con)
04905 {
04906    return con ? con->name : NULL;
04907 }
04908 
04909 char *ast_get_extension_name(struct ast_exten *exten)
04910 {
04911    return exten ? exten->exten : NULL;
04912 }
04913 
04914 char *ast_get_include_name(struct ast_include *inc)
04915 {
04916    return inc ? inc->name : NULL;
04917 }
04918 
04919 char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
04920 {
04921    return ip ? ip->pattern : NULL;
04922 }
04923 
04924 int ast_get_extension_priority(struct ast_exten *exten)
04925 {
04926    return exten ? exten->priority : -1;
04927 }
04928 
04929 /*
04930  * Registrar info functions ...
04931  */
04932 char *ast_get_context_registrar(struct ast_context *c)
04933 {
04934    return c ? c->registrar : NULL;
04935 }
04936 
04937 char *ast_get_extension_registrar(struct ast_exten *e)
04938 {
04939    return e ? e->registrar : NULL;
04940 }
04941 
04942 char *ast_get_include_registrar(struct ast_include *i)
04943 {
04944    return i ? i->registrar : NULL;
04945 }
04946 
04947 char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
04948 {
04949    return ip ? ip->registrar : NULL;
04950 }
04951 
04952 int ast_get_extension_matchcid(struct ast_exten *e)
04953 {
04954    return e ? e->matchcid : 0;
04955 }
04956 
04957 char *ast_get_extension_cidmatch(struct ast_exten *e)
04958 {
04959    return e ? e->cidmatch : NULL;
04960 }
04961 
04962 char *ast_get_extension_app(struct ast_exten *e)
04963 {
04964    return e ? e->app : NULL;
04965 }
04966 
04967 void *ast_get_extension_app_data(struct ast_exten *e)
04968 {
04969    return e ? e->data : NULL;
04970 }
04971 
04972 char *ast_get_switch_name(struct ast_sw *sw)
04973 {
04974    return sw ? sw->name : NULL;
04975 }
04976 
04977 char *ast_get_switch_data(struct ast_sw *sw)
04978 {
04979    return sw ? sw->data : NULL;
04980 }
04981 
04982 char *ast_get_switch_registrar(struct ast_sw *sw)
04983 {
04984    return sw ? sw->registrar : NULL;
04985 }
04986 
04987 /*
04988  * Walking functions ...
04989  */
04990 struct ast_context *ast_walk_contexts(struct ast_context *con)
04991 {
04992    if (!con)
04993       return contexts;
04994    else
04995       return con->next;
04996 }
04997 
04998 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
04999    struct ast_exten *exten)
05000 {
05001    if (!exten)
05002       return con ? con->root : NULL;
05003    else
05004       return exten->next;
05005 }
05006 
05007 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
05008    struct ast_sw *sw)
05009 {
05010    if (!sw)
05011       return con ? con->alts : NULL;
05012    else
05013       return sw->next;
05014 }
05015 
05016 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
05017    struct ast_exten *priority)
05018 {
05019    if (!priority)
05020       return exten;
05021    else
05022       return priority->peer;
05023 }
05024 
05025 struct ast_include *ast_walk_context_includes(struct ast_context *con,
05026    struct ast_include *inc)
05027 {
05028    if (!inc)
05029       return con ? con->includes : NULL;
05030    else
05031       return inc->next;
05032 }
05033 
05034 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
05035    struct ast_ignorepat *ip)
05036 {
05037    if (!ip)
05038       return con ? con->ignorepats : NULL;
05039    else
05040       return ip->next;
05041 }
05042 
05043 int ast_context_verify_includes(struct ast_context *con)
05044 {
05045    struct ast_include *inc;
05046    int res = 0;
05047 
05048    for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
05049       if (!ast_context_find(inc->rname)) {
05050          res = -1;
05051          ast_log(LOG_WARNING, "Context '%s' tries includes non-existant context '%s'\n",
05052                ast_get_context_name(con), inc->rname);
05053       }
05054    return res;
05055 }

Generated on Thu Oct 28 11:32:55 2004 for Asterisk by doxygen1.2.15