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

Generated on Wed Aug 10 11:36:32 2005 for Asterisk by  doxygen 1.4.4