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

Generated on Sat Nov 25 19:09:44 2006 for Asterisk by  doxygen 1.4.2