Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:54 2009

## Asterisk developer's documentation

- Main Page
- Related Pages
- Modules
- Data Structures
- Files
- Directories

# pbx.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  */
    00018
    00019 /*! \file
    00020  *
    00021  * \brief Core PBX routines.
    00022  *
    00023  */
    00024
    00025 #include <sys/types.h>
    00026 #include <string.h>
    00027 #include <unistd.h>
    00028 #include <stdlib.h>
    00029 #include <stdio.h>
    00030 #include <ctype.h>
    00031 #include <errno.h>
    00032 #include <time.h>
    00033 #include <sys/time.h>
    00034
    00035 #include "asterisk.h"
    00036
    00037 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 221754 $")
    00038
    00039 #include "asterisk/lock.h"
    00040 #include "asterisk/cli.h"
    00041 #include "asterisk/pbx.h"
    00042 #include "asterisk/channel.h"
    00043 #include "asterisk/options.h"
    00044 #include "asterisk/logger.h"
    00045 #include "asterisk/file.h"
    00046 #include "asterisk/callerid.h"
    00047 #include "asterisk/cdr.h"
    00048 #include "asterisk/config.h"
    00049 #include "asterisk/term.h"
    00050 #include "asterisk/manager.h"
    00051 #include "asterisk/ast_expr.h"
    00052 #include "asterisk/linkedlists.h"
    00053 #include "asterisk/say.h"
    00054 #include "asterisk/utils.h"
    00055 #include "asterisk/causes.h"
    00056 #include "asterisk/musiconhold.h"
    00057 #include "asterisk/app.h"
    00058 #include "asterisk/devicestate.h"
    00059 #include "asterisk/compat.h"
    00060
    00061 /*!
    00062  * \note I M P O R T A N T :
    00063  *
    00064  *    The speed of extension handling will likely be among the most important
    00065  * aspects of this PBX.  The switching scheme as it exists right now isn't
    00066  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
    00067  * of priorities, but a constant search time here would be great ;-)
    00068  *
    00069  */
    00070
    00071 #ifdef LOW_MEMORY
    00072 #define EXT_DATA_SIZE 256
    00073 #else
    00074 #define EXT_DATA_SIZE 8192
    00075 #endif
    00076
    00077 #define SWITCH_DATA_LENGTH 256
    00078
    00079 #define VAR_BUF_SIZE 4096
    00080
    00081 #define  VAR_NORMAL     1
    00082 #define  VAR_SOFTTRAN   2
    00083 #define  VAR_HARDTRAN   3
    00084
    00085 #define BACKGROUND_SKIP    (1 << 0)
    00086 #define BACKGROUND_NOANSWER   (1 << 1)
    00087 #define BACKGROUND_MATCHEXTEN (1 << 2)
    00088 #define BACKGROUND_PLAYBACK   (1 << 3)
    00089
    00090 AST_APP_OPTIONS(background_opts, {
    00091    AST_APP_OPTION('s', BACKGROUND_SKIP),
    00092    AST_APP_OPTION('n', BACKGROUND_NOANSWER),
    00093    AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
    00094    AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
    00095 });
    00096
    00097 #define WAITEXTEN_MOH      (1 << 0)
    00098
    00099 AST_APP_OPTIONS(waitexten_opts, {
    00100    AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
    00101 });
    00102
    00103 struct ast_context;
    00104
    00105 /*!\brief ast_exten: An extension
    00106    The dialplan is saved as a linked list with each context
    00107    having it's own linked list of extensions - one item per
    00108    priority.
    00109 */
    00110 struct ast_exten {
    00111    char *exten;         /* Extension name */
    00112    int matchcid;        /* Match caller id ? */
    00113    char *cidmatch;         /* Caller id to match for this extension */
    00114    int priority;        /* Priority */
    00115    char *label;         /* Label */
    00116    struct ast_context *parent;   /* The context this extension belongs to  */
    00117    char *app;        /* Application to execute */
    00118    void *data;       /* Data to use (arguments) */
    00119    void (*datad)(void *);     /* Data destructor */
    00120    struct ast_exten *peer;    /* Next higher priority with our extension */
    00121    const char *registrar;     /* Registrar */
    00122    struct ast_exten *next;    /* Extension with a greater ID */
    00123    char stuff[0];
    00124 };
    00125
    00126 /*! \brief ast_include: include= support in extensions.conf */
    00127 struct ast_include {
    00128    char *name;
    00129    char *rname;      /* Context to include */
    00130    const char *registrar;        /* Registrar */
    00131    int hastime;            /* If time construct exists */
    00132    struct ast_timing timing;               /* time construct */
    00133    struct ast_include *next;     /* Link them together */
    00134    char stuff[0];
    00135 };
    00136
    00137 /*! \brief ast_sw: Switch statement in extensions.conf */
    00138 struct ast_sw {
    00139    char *name;
    00140    const char *registrar;        /* Registrar */
    00141    char *data;          /* Data load */
    00142    int eval;
    00143    struct ast_sw *next;       /* Link them together */
    00144    char *tmpdata;
    00145    char stuff[0];
    00146 };
    00147
    00148 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
    00149 struct ast_ignorepat {
    00150    const char *registrar;
    00151    struct ast_ignorepat *next;
    00152    char pattern[0];
    00153 };
    00154
    00155 /*! \brief ast_context: An extension context */
    00156 struct ast_context {
    00157    ast_mutex_t lock;          /*!< A lock to prevent multiple threads from clobbering the context */
    00158    struct ast_exten *root;       /*!< The root of the list of extensions */
    00159    struct ast_context *next;     /*!< Link them together */
    00160    struct ast_include *includes;    /*!< Include other contexts */
    00161    struct ast_ignorepat *ignorepats;   /*!< Patterns for which to continue playing dialtone */
    00162    const char *registrar;        /*!< Registrar */
    00163    struct ast_sw *alts;       /*!< Alternative switches */
    00164    char name[0];           /*!< Name of the context */
    00165 };
    00166
    00167
    00168 /*! \brief ast_app: A registered application */
    00169 struct ast_app {
    00170    int (*execute)(struct ast_channel *chan, void *data);
    00171    const char *synopsis;         /* Synopsis text for 'show applications' */
    00172    const char *description;      /* Description (help text) for 'show application <name>' */
    00173    struct ast_app *next;         /* Next app in list */
    00174    char name[0];           /* Name of the application */
    00175 };
    00176
    00177 /*! \brief ast_state_cb: An extension state notify register item */
    00178 struct ast_state_cb {
    00179    int id;
    00180    void *data;
    00181    ast_state_cb_type callback;
    00182    struct ast_state_cb *next;
    00183 };
    00184
    00185 /*! \brief Structure for dial plan hints
    00186
    00187   Hints are pointers from an extension in the dialplan to one or
    00188   more devices (tech/name) */
    00189 struct ast_hint {
    00190    struct ast_exten *exten;   /*!< Extension */
    00191    int laststate;          /*!< Last known state */
    00192    struct ast_state_cb *callbacks;  /*!< Callback list for this extension */
    00193    struct ast_hint *next;     /*!< Pointer to next hint in list */
    00194 };
    00195
    00196 int ast_pbx_outgoing_cdr_failed(void);
    00197
    00198 static int pbx_builtin_answer(struct ast_channel *, void *);
    00199 static int pbx_builtin_goto(struct ast_channel *, void *);
    00200 static int pbx_builtin_hangup(struct ast_channel *, void *);
    00201 static int pbx_builtin_background(struct ast_channel *, void *);
    00202 static int pbx_builtin_dtimeout(struct ast_channel *, void *);
    00203 static int pbx_builtin_rtimeout(struct ast_channel *, void *);
    00204 static int pbx_builtin_atimeout(struct ast_channel *, void *);
    00205 static int pbx_builtin_wait(struct ast_channel *, void *);
    00206 static int pbx_builtin_waitexten(struct ast_channel *, void *);
    00207 static int pbx_builtin_setlanguage(struct ast_channel *, void *);
    00208 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
    00209 static int pbx_builtin_setaccount(struct ast_channel *, void *);
    00210 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
    00211 static int pbx_builtin_ringing(struct ast_channel *, void *);
    00212 static int pbx_builtin_progress(struct ast_channel *, void *);
    00213 static int pbx_builtin_congestion(struct ast_channel *, void *);
    00214 static int pbx_builtin_busy(struct ast_channel *, void *);
    00215 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
    00216 static int pbx_builtin_noop(struct ast_channel *, void *);
    00217 static int pbx_builtin_gotoif(struct ast_channel *, void *);
    00218 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
    00219 static int pbx_builtin_execiftime(struct ast_channel *, void *);
    00220 static int pbx_builtin_saynumber(struct ast_channel *, void *);
    00221 static int pbx_builtin_saydigits(struct ast_channel *, void *);
    00222 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
    00223 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
    00224 static int pbx_builtin_setvar_old(struct ast_channel *, void *);
    00225 int pbx_builtin_setvar(struct ast_channel *, void *);
    00226 static int pbx_builtin_importvar(struct ast_channel *, void *);
    00227
    00228 AST_MUTEX_DEFINE_STATIC(globalslock);
    00229 static struct varshead globals;
    00230
    00231 static int autofallthrough = 0;
    00232
    00233 AST_MUTEX_DEFINE_STATIC(maxcalllock);
    00234 static int countcalls = 0;
    00235
    00236 AST_MUTEX_DEFINE_STATIC(acflock);      /*!< Lock for the custom function list */
    00237 static struct ast_custom_function *acf_root = NULL;
    00238
    00239 /*! \brief Declaration of builtin applications */
    00240 static struct pbx_builtin {
    00241    char name[AST_MAX_APP];
    00242    int (*execute)(struct ast_channel *chan, void *data);
    00243    char *synopsis;
    00244    char *description;
    00245 } builtins[] =
    00246 {
    00247    /* These applications are built into the PBX core and do not
    00248       need separate modules */
    00249
    00250    { "AbsoluteTimeout", pbx_builtin_atimeout,
    00251    "Set absolute maximum time of call",
    00252    "  AbsoluteTimeout(seconds): This application will set the absolute maximum\n"
    00253    "amount of time permitted for a call. A setting of 0 disables the timeout.\n"
    00254    "  AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout)\n"
    00255    },
    00256
    00257    { "Answer", pbx_builtin_answer,
    00258    "Answer a channel if ringing",
    00259    "  Answer([delay]): If the call has not been answered, this application will\n"
    00260    "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
    00261    "Asterisk will wait this number of milliseconds before returning to\n"
    00262    "the dialplan after answering the call.\n"
    00263    },
    00264
    00265    { "BackGround", pbx_builtin_background,
    00266    "Play a file while awaiting extension",
    00267    "  Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
    00268    "This application will play the given list of files while waiting for an\n"
    00269    "extension to be dialed by the calling channel. To continue waiting for digits\n"
    00270    "after this application has finished playing files, the WaitExten application\n"
    00271    "should be used. The 'langoverride' option explicity specifies which language\n"
    00272    "to attempt to use for the requested sound files. If a 'context' is specified,\n"
    00273    "this is the dialplan context that this application will use when exiting to a\n"
    00274    "dialed extension."
    00275    "  If one of the requested sound files does not exist, call processing will be\n"
    00276    "terminated.\n"
    00277    "  Options:\n"
    00278    "    s - causes the playback of the message to be skipped\n"
    00279    "          if the channel is not in the 'up' state (i.e. it\n"
    00280    "          hasn't been answered yet.) If this happens, the\n"
    00281    "          application will return immediately.\n"
    00282    "    n - don't answer the channel before playing the files\n"
    00283    "    m - only break if a digit hit matches a one digit\n"
    00284    "          extension in the destination context\n"
    00285    },
    00286
    00287    { "Busy", pbx_builtin_busy,
    00288    "Indicate the Busy condition",
    00289    "  Busy([timeout]): This application will indicate the busy condition to\n"
    00290    "the calling channel. If the optional timeout is specified, the calling channel\n"
    00291    "will be hung up after the specified number of seconds. Otherwise, this\n"
    00292    "application will wait until the calling channel hangs up.\n"
    00293    },
    00294
    00295    { "Congestion", pbx_builtin_congestion,
    00296    "Indicate the Congestion condition",
    00297    "  Congestion([timeout]): This application will indicate the congenstion\n"
    00298    "condition to the calling channel. If the optional timeout is specified, the\n"
    00299    "calling channel will be hung up after the specified number of seconds.\n"
    00300    "Otherwise, this application will wait until the calling channel hangs up.\n"
    00301    },
    00302
    00303    { "DigitTimeout", pbx_builtin_dtimeout,
    00304    "Set maximum timeout between digits",
    00305    "  DigitTimeout(seconds): Set the maximum amount of time permitted between\n"
    00306    "digits when the user is typing in an extension. When this timeout expires,\n"
    00307    "after the user has started to type in an extension, the extension will be\n"
    00308    "considered complete, and will be interpreted. Note that if an extension\n"
    00309    "typed in is valid, it will not have to timeout to be tested, so typically\n"
    00310    "at the expiry of this timeout, the extension will be considered invalid\n"
    00311    "(and thus control would be passed to the 'i' extension, or if it doesn't\n"
    00312    "exist the call would be terminated). The default timeout is 5 seconds.\n"
    00313    "  DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout)\n"
    00314    },
    00315
    00316    { "Goto", pbx_builtin_goto,
    00317    "Jump to a particular priority, extension, or context",
    00318    "  Goto([[context|]extension|]priority): This application will set the current\n"
    00319    "context, extension, and priority in the channel structure. After it completes, the\n"
    00320    "pbx engine will continue dialplan execution at the specified location.\n"
    00321    "If no specific extension, or extension and context, are specified, then this\n"
    00322    "application will just set the specified priority of the current extension.\n"
    00323    "  At least a priority is required as an argument, or the goto will return a -1,\n"
    00324    "and the channel and call will be terminated.\n"
    00325    "  If the location that is put into the channel information is bogus, and asterisk cannot\n"
    00326         "find that location in the dialplan,\n"
    00327    "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
    00328    "extension in the current context. If that does not exist, it will try to execute the\n"
    00329    "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
    00330    "channel is hung up, and the execution of instructions on the channel is terminated.\n"
    00331    "What this means is that, for example, you specify a context that does not exist, then\n"
    00332    "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
    00333    },
    00334
    00335    { "GotoIf", pbx_builtin_gotoif,
    00336    "Conditional goto",
    00337    "  GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
    00338    "context, extension, and priority in the channel structure based on the evaluation of\n"
    00339    "the given condition. After this application completes, the\n"
    00340    "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
    00341    "The channel will continue at\n"
    00342    "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
    00343    "false. The labels are specified with the same syntax as used within the Goto\n"
    00344    "application.  If the label chosen by the condition is omitted, no jump is\n"
    00345    "performed, and the execution passes to the next instruction.\n"
    00346    "If the target location is bogus, and does not exist, the execution engine will try \n"
    00347    "to find and execute the code in the 'i' (invalid)\n"
    00348    "extension in the current context. If that does not exist, it will try to execute the\n"
    00349    "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
    00350    "channel is hung up, and the execution of instructions on the channel is terminated.\n"
    00351    "Remember that this command can set the current context, and if the context specified\n"
    00352    "does not exist, then it will not be able to find any 'h' or 'i' extensions there,\n"
    00353    "and the channel and call will both be terminated!\n"
    00354    },
    00355
    00356    { "GotoIfTime", pbx_builtin_gotoiftime,
    00357    "Conditional Goto based on the current time",
    00358    "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
    00359    "This application will set the context, extension, and priority in the channel structure\n"
    00360    "if the current time matches the given time specification. Otherwise, nothing is done.\n"
    00361    "Further information on the time specification can be found in examples\n"
    00362    "illustrating how to do time-based context includes in the dialplan.\n"
    00363    "If the target jump location is bogus, Asterisk will respond as outlined in Goto.\n"
    00364    },
    00365
    00366    { "ExecIfTime", pbx_builtin_execiftime,
    00367    "Conditional application execution based on the current time",
    00368    "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
    00369    "This application will execute the specified dialplan application, with optional\n"
    00370    "arguments, if the current time matches the given time specification. Further\n"
    00371    "information on the time speicification can be found in examples illustrating\n"
    00372    "how to do time-based context includes in the dialplan.\n"
    00373    },
    00374
    00375    { "Hangup", pbx_builtin_hangup,
    00376    "Hang up the calling channel",
    00377    "  Hangup(): This application will hang up the calling channel.\n"
    00378    },
    00379
    00380    { "NoOp", pbx_builtin_noop,
    00381    "Do Nothing",
    00382    "  NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
    00383    "purposes. Any text that is provided as arguments to this application can be\n"
    00384    "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
    00385    "variables or functions without having any effect."
    00386    },
    00387
    00388    { "Progress", pbx_builtin_progress,
    00389    "Indicate progress",
    00390    "  Progress(): This application will request that in-band progress information\n"
    00391    "be provided to the calling channel.\n"
    00392    },
    00393
    00394    { "ResetCDR", pbx_builtin_resetcdr,
    00395    "Resets the Call Data Record",
    00396    "  ResetCDR([options]):  This application causes the Call Data Record to be\n"
    00397    "reset.\n"
    00398    "  Options:\n"
    00399    "    w -- Store the current CDR record before resetting it.\n"
    00400    "    a -- Store any stacked records.\n"
    00401    "    v -- Save CDR variables.\n"
    00402    },
    00403
    00404    { "ResponseTimeout", pbx_builtin_rtimeout,
    00405    "Set maximum timeout awaiting response",
    00406    "  ResponseTimeout(seconds): This will set the maximum amount of time permitted\n"
    00407    "to wait for an extension to dialed (see the WaitExten application), before the\n"
    00408    "timeout occurs. If this timeout is reached, dialplan execution will continue at\n"
    00409    "the 't' extension, if it exists.\n"
    00410    "  ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout)\n"
    00411    },
    00412
    00413    { "Ringing", pbx_builtin_ringing,
    00414    "Indicate ringing tone",
    00415    "  Ringing(): This application will request that the channel indicate a ringing\n"
    00416    "tone to the user.\n"
    00417    },
    00418
    00419    { "SayNumber", pbx_builtin_saynumber,
    00420    "Say Number",
    00421    "  SayNumber(digits[,gender]): This application will play the sounds that\n"
    00422    "correspond to the given number. Optionally, a gender may be specified.\n"
    00423    "This will use the language that is currently set for the channel. See the\n"
    00424    "LANGUAGE function for more information on setting the language for the channel.\n"
    00425    },
    00426
    00427    { "SayDigits", pbx_builtin_saydigits,
    00428    "Say Digits",
    00429    "  SayDigits(digits): This application will play the sounds that correspond\n"
    00430    "to the digits of the given number. This will use the language that is currently\n"
    00431    "set for the channel. See the LANGUAGE function for more information on setting\n"
    00432    "the language for the channel.\n"
    00433    },
    00434
    00435    { "SayAlpha", pbx_builtin_saycharacters,
    00436    "Say Alpha",
    00437    "  SayAlpha(string): This application will play the sounds that correspond to\n"
    00438    "the letters of the given string.\n"
    00439    },
    00440
    00441    { "SayPhonetic", pbx_builtin_sayphonetic,
    00442    "Say Phonetic",
    00443    "  SayPhonetic(string): This application will play the sounds from the phonetic\n"
    00444    "alphabet that correspond to the letters in the given string.\n"
    00445    },
    00446
    00447    { "SetAccount", pbx_builtin_setaccount,
    00448    "Set the CDR Account Code",
    00449    "  SetAccount([account]): This application will set the channel account code for\n"
    00450    "billing purposes.\n"
    00451    "  SetAccount has been deprecated in favor of the Set(CDR(accountcode)=account).\n"
    00452    },
    00453
    00454    { "SetAMAFlags", pbx_builtin_setamaflags,
    00455    "Set the AMA Flags",
    00456    "  SetAMAFlags([flag]): This channel will set the channel's AMA Flags for billing\n"
    00457    "purposes.\n"
    00458    },
    00459
    00460    { "SetGlobalVar", pbx_builtin_setglobalvar,
    00461    "Set a global variable to a given value",
    00462    "  SetGlobalVar(variable=value): This application sets a given global variable to\n"
    00463    "the specified value.\n"
    00464    },
    00465
    00466    { "SetLanguage", pbx_builtin_setlanguage,
    00467    "Set the channel's preferred language",
    00468    "  SetLanguage(language): This will set the channel language to the given value.\n"
    00469    "This information is used for the syntax in generation of numbers, and to choose\n"
    00470    "a sound file in the given language, when it is available.\n"
    00471    "  For example, if language is set to 'fr' and the file 'demo-congrats' is \n"
    00472    "requested to be played, if the file 'fr/demo-congrats' exists, then\n"
    00473    "it will play that file. If not, it will play the normal 'demo-congrats'.\n"
    00474    "For some language codes, SetLanguage also changes the syntax of some\n"
    00475    "Asterisk functions, like SayNumber.\n"
    00476    "  SetLanguage has been deprecated in favor of Set(LANGUAGE()=language)\n"
    00477    },
    00478
    00479    { "Set", pbx_builtin_setvar,
    00480    "Set channel variable(s) or function value(s)",
    00481    "  Set(name1=value1|name2=value2|..[|options])\n"
    00482    "This function can be used to set the value of channel variables or dialplan\n"
    00483    "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
    00484    "if the variable name is prefixed with _, the variable will be inherited into\n"
    00485    "channels created from the current channel. If the variable name is prefixed\n"
    00486    "with __, the variable will be inherited into channels created from the current\n"
    00487    "channel and all children channels.\n"
    00488    "  Options:\n"
    00489    "    g - Set variable globally instead of on the channel\n"
    00490    "        (applies only to variables, not functions)\n"
    00491    },
    00492
    00493    { "SetVar", pbx_builtin_setvar_old,
    00494    "Set channel variable(s)",
    00495    "  SetVar(name1=value1|name2=value2|..[|options]): This application has been\n"
    00496    "deprecated in favor of using the Set application.\n"
    00497    },
    00498
    00499    { "ImportVar", pbx_builtin_importvar,
    00500    "Import a variable from a channel into a new variable",
    00501    "  ImportVar(newvar=channelname|variable): This application imports a variable\n"
    00502    "from the specified channel (as opposed to the current one) and stores it as\n"
    00503    "a variable in the current channel (the channel that is calling this\n"
    00504    "application). Variables created by this application have the same inheritance\n"
    00505    "properties as those created with the Set application. See the documentation for\n"
    00506    "Set for more information.\n"
    00507    },
    00508
    00509    { "Wait", pbx_builtin_wait,
    00510    "Waits for some time",
    00511    "  Wait(seconds): This application waits for a specified number of seconds.\n"
    00512    "Then, dialplan execution will continue at the next priority.\n"
    00513    "  Note that the seconds can be passed with fractions of a second. For example,\n"
    00514    "'1.5' will ask the application to wait for 1.5 seconds.\n"
    00515    },
    00516
    00517    { "WaitExten", pbx_builtin_waitexten,
    00518    "Waits for an extension to be entered",
    00519    "  WaitExten([seconds][|options]): This application waits for the user to enter\n"
    00520    "a new extension for a specified number of seconds.\n"
    00521    "  Note that the seconds can be passed with fractions of a second. For example,\n"
    00522    "'1.5' will ask the application to wait for 1.5 seconds.\n"
    00523    "  Options:\n"
    00524    "    m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
    00525    "               Optionally, specify the class for music on hold within parenthesis.\n"
    00526    },
    00527
    00528 };
    00529
    00530 static struct ast_context *contexts = NULL;
    00531 AST_MUTEX_DEFINE_STATIC(conlock);      /* Lock for the ast_context list */
    00532 static struct ast_app *apps = NULL;
    00533 AST_MUTEX_DEFINE_STATIC(applock);      /* Lock for the application list */
    00534
    00535 struct ast_switch *switches = NULL;
    00536 AST_MUTEX_DEFINE_STATIC(switchlock);      /* Lock for switches */
    00537
    00538 /* WARNING:
    00539    When holding this lock, do _not_ do anything that will cause conlock
    00540    to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
    00541    function will take the locks in conlock/hintlock order, so any other
    00542    paths that require both locks must also take them in that order.
    00543 */
    00544 AST_MUTEX_DEFINE_STATIC(hintlock);     /* Lock for extension state notifys */
    00545 static int stateid = 1;
    00546 struct ast_hint *hints = NULL;
    00547 struct ast_state_cb *statecbs = NULL;
    00548
    00549 /*
    00550    \note This function is special. It saves the stack so that no matter
    00551    how many times it is called, it returns to the same place */
    00552 int pbx_exec(struct ast_channel *c,       /*!< Channel */
    00553       struct ast_app *app,    /*!< Application */
    00554       void *data,       /*!< Data for execution */
    00555       int newstack)        /*!< Force stack increment */
    00556 {
    00557    int res;
    00558
    00559    char *saved_c_appl;
    00560    char *saved_c_data;
    00561
    00562    int (*execute)(struct ast_channel *chan, void *data) = app->execute;
    00563
    00564    if (newstack) {
    00565       if (c->cdr && !ast_check_hangup(c))
    00566          ast_cdr_setapp(c->cdr, app->name, data);
    00567
    00568       /* save channel values */
    00569       saved_c_appl= c->appl;
    00570       saved_c_data= c->data;
    00571
    00572       c->appl = app->name;
    00573       c->data = data;
    00574       res = execute(c, data);
    00575       /* restore channel values */
    00576       c->appl= saved_c_appl;
    00577       c->data= saved_c_data;
    00578       return res;
    00579    } else
    00580       ast_log(LOG_WARNING, "You really didn't want to call this function with newstack set to 0\n");
    00581    return -1;
    00582 }
    00583
    00584
    00585 /*! Go no deeper than this through includes (not counting loops) */
    00586 #define AST_PBX_MAX_STACK  128
    00587
    00588 #define HELPER_EXISTS 0
    00589 #define HELPER_SPAWN 1
    00590 #define HELPER_EXEC 2
    00591 #define HELPER_CANMATCH 3
    00592 #define HELPER_MATCHMORE 4
    00593 #define HELPER_FINDLABEL 5
    00594
    00595 /*! \brief Find application handle in linked list
    00596  */
    00597 struct ast_app *pbx_findapp(const char *app)
    00598 {
    00599    struct ast_app *tmp;
    00600
    00601    if (ast_mutex_lock(&applock)) {
    00602       ast_log(LOG_WARNING, "Unable to obtain application lock\n");
    00603       return NULL;
    00604    }
    00605    tmp = apps;
    00606    while(tmp) {
    00607       if (!strcasecmp(tmp->name, app))
    00608          break;
    00609       tmp = tmp->next;
    00610    }
    00611    ast_mutex_unlock(&applock);
    00612    return tmp;
    00613 }
    00614
    00615 static struct ast_switch *pbx_findswitch(const char *sw)
    00616 {
    00617    struct ast_switch *asw;
    00618
    00619    if (ast_mutex_lock(&switchlock)) {
    00620       ast_log(LOG_WARNING, "Unable to obtain application lock\n");
    00621       return NULL;
    00622    }
    00623    asw = switches;
    00624    while(asw) {
    00625       if (!strcasecmp(asw->name, sw))
    00626          break;
    00627       asw = asw->next;
    00628    }
    00629    ast_mutex_unlock(&switchlock);
    00630    return asw;
    00631 }
    00632
    00633 static inline int include_valid(struct ast_include *i)
    00634 {
    00635    if (!i->hastime)
    00636       return 1;
    00637
    00638    return ast_check_timing(&(i->timing));
    00639 }
    00640
    00641 static void pbx_destroy(struct ast_pbx *p)
    00642 {
    00643    free(p);
    00644 }
    00645
    00646 #define EXTENSION_MATCH_CORE(data,pattern,match) {\
    00647    /* All patterns begin with _ */\
    00648    if (pattern[0] != '_') \
    00649       return 0;\
    00650    /* Start optimistic */\
    00651    match=1;\
    00652    pattern++;\
    00653    while(match && *data && *pattern && (*pattern != '/')) {\
    00654       while (*data == '-' && (*(data+1) != '\0')) data++;\
    00655       switch(toupper(*pattern)) {\
    00656       case '[': \
    00657       {\
    00658          int i,border=0;\
    00659          char *where;\
    00660          match=0;\
    00661          pattern++;\
    00662          where=strchr(pattern,']');\
    00663          if (where)\
    00664             border=(int)(where-pattern);\
    00665          if (!where || border > strlen(pattern)) {\
    00666             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
    00667             return match;\
    00668          }\
    00669          for (i=0; i<border; i++) {\
    00670             int res=0;\
    00671             if (i+2<border)\
    00672                if (pattern[i+1]=='-') {\
    00673                   if (*data >= pattern[i] && *data <= pattern[i+2]) {\
    00674                      res=1;\
    00675                   } else {\
    00676                      i+=2;\
    00677                      continue;\
    00678                   }\
    00679                }\
    00680             if (res==1 || *data==pattern[i]) {\
    00681                match = 1;\
    00682                break;\
    00683             }\
    00684          }\
    00685          pattern+=border;\
    00686          break;\
    00687       }\
    00688       case 'N':\
    00689          if ((*data < '2') || (*data > '9'))\
    00690             match=0;\
    00691          break;\
    00692       case 'X':\
    00693          if ((*data < '0') || (*data > '9'))\
    00694             match = 0;\
    00695          break;\
    00696       case 'Z':\
    00697          if ((*data < '1') || (*data > '9'))\
    00698             match = 0;\
    00699          break;\
    00700       case '.':\
    00701          /* Must match */\
    00702          return 1;\
    00703       case '!':\
    00704          /* Early match */\
    00705          return 2;\
    00706       case ' ':\
    00707       case '-':\
    00708          /* Ignore these characters */\
    00709          data--;\
    00710          break;\
    00711       default:\
    00712          if (*data != *pattern)\
    00713             match =0;\
    00714       }\
    00715       data++;\
    00716       pattern++;\
    00717    }\
    00718    /* If we ran off the end of the data and the pattern ends in '!', match */\
    00719    if (match && !*data && (*pattern == '!'))\
    00720       return 2;\
    00721 }
    00722
    00723 int ast_extension_match(const char *pattern, const char *data)
    00724 {
    00725    int match;
    00726    /* If they're the same return */
    00727    if (!strcmp(pattern, data))
    00728       return 1;
    00729    EXTENSION_MATCH_CORE(data,pattern,match);
    00730    /* Must be at the end of both */
    00731    if (*data || (*pattern && (*pattern != '/')))
    00732       match = 0;
    00733    return match;
    00734 }
    00735
    00736 int ast_extension_close(const char *pattern, const char *data, int needmore)
    00737 {
    00738    int match;
    00739    /* If "data" is longer, it can'be a subset of pattern unless
    00740       pattern is a pattern match */
    00741    if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
    00742       return 0;
    00743
    00744    if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
    00745       (!needmore || (strlen(pattern) > strlen(data)))) {
    00746       return 1;
    00747    }
    00748    EXTENSION_MATCH_CORE(data,pattern,match);
    00749    /* If there's more or we don't care about more, or if it's a possible early match,
    00750       return non-zero; otherwise it's a miss */
    00751    if (!needmore || *pattern || match == 2) {
    00752       return match;
    00753    } else
    00754       return 0;
    00755 }
    00756
    00757 struct ast_context *ast_context_find(const char *name)
    00758 {
    00759    struct ast_context *tmp;
    00760    ast_mutex_lock(&conlock);
    00761    if (name) {
    00762       tmp = contexts;
    00763       while(tmp) {
    00764          if (!strcasecmp(name, tmp->name))
    00765             break;
    00766          tmp = tmp->next;
    00767       }
    00768    } else
    00769       tmp = contexts;
    00770    ast_mutex_unlock(&conlock);
    00771    return tmp;
    00772 }
    00773
    00774 #define STATUS_NO_CONTEXT  1
    00775 #define STATUS_NO_EXTENSION   2
    00776 #define STATUS_NO_PRIORITY 3
    00777 #define STATUS_NO_LABEL    4
    00778 #define STATUS_SUCCESS     5
    00779
    00780 static int matchcid(const char *cidpattern, const char *callerid)
    00781 {
    00782    int failresult;
    00783
    00784    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
    00785       failing to get a number should count as a match, otherwise not */
    00786
    00787    if (!ast_strlen_zero(cidpattern))
    00788       failresult = 0;
    00789    else
    00790       failresult = 1;
    00791
    00792    if (!callerid)
    00793       return failresult;
    00794
    00795    return ast_extension_match(cidpattern, callerid);
    00796 }
    00797
    00798 static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast_context *bypass, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action, char *incstack[], int *stacklen, int *status, struct ast_switch **swo, char **data, const char **foundcontext)
    00799 {
    00800    int x, res;
    00801    struct ast_context *tmp;
    00802    struct ast_exten *e, *eroot;
    00803    struct ast_include *i;
    00804    struct ast_sw *sw;
    00805    struct ast_switch *asw;
    00806
    00807    /* Initialize status if appropriate */
    00808    if (!*stacklen) {
    00809       *status = STATUS_NO_CONTEXT;
    00810       *swo = NULL;
    00811       *data = NULL;
    00812    }
    00813    /* Check for stack overflow */
    00814    if (*stacklen >= AST_PBX_MAX_STACK) {
    00815       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
    00816       return NULL;
    00817    }
    00818    /* Check first to see if we've already been checked */
    00819    for (x=0; x<*stacklen; x++) {
    00820       if (!strcasecmp(incstack[x], context))
    00821          return NULL;
    00822    }
    00823    if (bypass)
    00824       tmp = bypass;
    00825    else
    00826       tmp = contexts;
    00827    while(tmp) {
    00828       /* Match context */
    00829       if (bypass || !strcmp(tmp->name, context)) {
    00830          struct ast_exten *earlymatch = NULL;
    00831
    00832          if (*status < STATUS_NO_EXTENSION)
    00833             *status = STATUS_NO_EXTENSION;
    00834          for (eroot = tmp->root; eroot; eroot=eroot->next) {
    00835             int match = 0;
    00836             /* Match extension */
    00837             if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
    00838                  ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
    00839                  ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
    00840                 (!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
    00841
    00842                if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
    00843                   /* It matched an extension ending in a '!' wildcard
    00844                      So ignore it for now, unless there's a better match */
    00845                   earlymatch = eroot;
    00846                } else {
    00847                   e = eroot;
    00848                   if (*status < STATUS_NO_PRIORITY)
    00849                      *status = STATUS_NO_PRIORITY;
    00850                   while(e) {
    00851                      /* Match priority */
    00852                      if (action == HELPER_FINDLABEL) {
    00853                         if (*status < STATUS_NO_LABEL)
    00854                            *status = STATUS_NO_LABEL;
    00855                         if (label && e->label && !strcmp(label, e->label)) {
    00856                            *status = STATUS_SUCCESS;
    00857                            *foundcontext = context;
    00858                            return e;
    00859                         }
    00860                      } else if (e->priority == priority) {
    00861                         *status = STATUS_SUCCESS;
    00862                         *foundcontext = context;
    00863                         return e;
    00864                      }
    00865                      e = e->peer;
    00866                   }
    00867                }
    00868             }
    00869          }
    00870          if (earlymatch) {
    00871             /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
    00872                of the loop waiting for more digits, and _then_ match (normally)
    00873                the extension we ended up with. We got an early-matching wildcard
    00874                pattern, so return NULL to break out of the loop. */
    00875             return NULL;
    00876          }
    00877          /* Check alternative switches */
    00878          sw = tmp->alts;
    00879          while(sw) {
    00880             if ((asw = pbx_findswitch(sw->name))) {
    00881                /* Substitute variables now */
    00882                if (sw->eval)
    00883                   pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
    00884                if (action == HELPER_CANMATCH)
    00885                   res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
    00886                else if (action == HELPER_MATCHMORE)
    00887                   res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
    00888                else
    00889                   res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
    00890                if (res) {
    00891                   /* Got a match */
    00892                   *swo = asw;
    00893                   *data = sw->eval ? sw->tmpdata : sw->data;
    00894                   *foundcontext = context;
    00895                   return NULL;
    00896                }
    00897             } else {
    00898                ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
    00899             }
    00900             sw = sw->next;
    00901          }
    00902          /* Setup the stack */
    00903          incstack[*stacklen] = tmp->name;
    00904          (*stacklen)++;
    00905          /* Now try any includes we have in this context */
    00906          i = tmp->includes;
    00907          while(i) {
    00908             if (include_valid(i)) {
    00909                if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
    00910                   return e;
    00911                if (*swo)
    00912                   return NULL;
    00913             }
    00914             i = i->next;
    00915          }
    00916          break;
    00917       }
    00918       tmp = tmp->next;
    00919    }
    00920    return NULL;
    00921 }
    00922
    00923 /* Note that it's negative -- that's important later. */
    00924 #define DONT_HAVE_LENGTH   0x80000000
    00925
    00926 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
    00927 {
    00928    char *varchar, *offsetchar = NULL;
    00929    int parens=0;
    00930
    00931    *offset = 0;
    00932    *length = DONT_HAVE_LENGTH;
    00933    *isfunc = 0;
    00934    for (varchar=var; *varchar; varchar++) {
    00935       switch (*varchar) {
    00936       case '(':
    00937          (*isfunc)++;
    00938          parens++;
    00939          break;
    00940       case ')':
    00941          parens--;
    00942          break;
    00943       case ':':
    00944          if (parens == 0) {
    00945             offsetchar = varchar + 1;
    00946             *varchar = '\0';
    00947             goto pvn_endfor;
    00948          }
    00949       }
    00950    }
    00951 pvn_endfor:
    00952    if (offsetchar) {
    00953       sscanf(offsetchar, "%30d:%30d", offset, length);
    00954       return 1;
    00955    } else {
    00956       return 0;
    00957    }
    00958 }
    00959
    00960 /*! \brief takes a substring. It is ok to call with value == workspace.
    00961  *
    00962  * offset < 0 means start from the end of the string and set the beginning
    00963  *   to be that many characters back.
    00964  * length is the length of the substring, -1 means unlimited
    00965  * (we take any negative value).
    00966  * Always return a copy in workspace.
    00967  */
    00968 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
    00969 {
    00970    char *ret = workspace;
    00971    int lr;  /* length of the input string after the copy */
    00972
    00973    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
    00974
    00975    if (offset == 0 && length < 0)   /* take the whole string */
    00976       return ret;
    00977
    00978    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
    00979
    00980    if (offset < 0)   {  /* translate negative offset into positive ones */
    00981       offset = lr + offset;
    00982       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
    00983          offset = 0;
    00984    }
    00985
    00986    /* too large offset result in empty string so we know what to return */
    00987    if (offset >= lr)
    00988       return ret + lr;  /* the final '\0' */
    00989
    00990    ret += offset;    /* move to the start position */
    00991    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
    00992       ret[length] = '\0';
    00993
    00994    return ret;
    00995 }
    00996
    00997 /*! \brief  pbx_retrieve_variable: Support for Asterisk built-in variables
    00998   ---*/
    00999 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
    01000 {
    01001    char tmpvar[80];
    01002    time_t thistime;
    01003    struct tm brokentime;
    01004    int offset, offset2, isfunc;
    01005    struct ast_var_t *variables;
    01006
    01007    if (c)
    01008       headp=&c->varshead;
    01009    *ret=NULL;
    01010    ast_copy_string(tmpvar, var, sizeof(tmpvar));
    01011    if (parse_variable_name(tmpvar, &offset, &offset2, &isfunc)) {
    01012       pbx_retrieve_variable(c, tmpvar, ret, workspace, workspacelen, headp);
    01013       if (!(*ret))
    01014          return;
    01015       *ret = substring(*ret, offset, offset2, workspace, workspacelen);
    01016    } else if (c && !strncmp(var, "CALL", 4)) {
    01017       if (!strncmp(var + 4, "ER", 2)) {
    01018          if (!strncmp(var + 6, "ID", 2)) {
    01019             if (!var[8]) {          /* CALLERID */
    01020                if (c->cid.cid_num) {
    01021                   if (c->cid.cid_name) {
    01022                      snprintf(workspace, workspacelen, "\"%s\" <%s>", c->cid.cid_name, c->cid.cid_num);
    01023                   } else {
    01024                      ast_copy_string(workspace, c->cid.cid_num, workspacelen);
    01025                   }
    01026                   *ret = workspace;
    01027                } else if (c->cid.cid_name) {
    01028                   ast_copy_string(workspace, c->cid.cid_name, workspacelen);
    01029                   *ret = workspace;
    01030                } else
    01031                   *ret = NULL;
    01032             } else if (!strcmp(var + 8, "NUM")) {
    01033                /* CALLERIDNUM */
    01034                if (c->cid.cid_num) {
    01035                   ast_copy_string(workspace, c->cid.cid_num, workspacelen);
    01036                   *ret = workspace;
    01037                } else
    01038                   *ret = NULL;
    01039             } else if (!strcmp(var + 8, "NAME")) {
    01040                /* CALLERIDNAME */
    01041                if (c->cid.cid_name) {
    01042                   ast_copy_string(workspace, c->cid.cid_name, workspacelen);
    01043                   *ret = workspace;
    01044                } else
    01045                   *ret = NULL;
    01046             } else
    01047                goto icky;
    01048          } else if (!strcmp(var + 6, "ANI")) {
    01049             /* CALLERANI */
    01050             if (c->cid.cid_ani) {
    01051                ast_copy_string(workspace, c->cid.cid_ani, workspacelen);
    01052                *ret = workspace;
    01053             } else
    01054                *ret = NULL;
    01055          } else
    01056             goto icky;
    01057       } else if (!strncmp(var + 4, "ING", 3)) {
    01058          if (!strcmp(var + 7, "PRES")) {
    01059             /* CALLINGPRES */
    01060             snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
    01061             *ret = workspace;
    01062          } else if (!strcmp(var + 7, "ANI2")) {
    01063             /* CALLINGANI2 */
    01064             snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
    01065             *ret = workspace;
    01066          } else if (!strcmp(var + 7, "TON")) {
    01067             /* CALLINGTON */
    01068             snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
    01069             *ret = workspace;
    01070          } else if (!strcmp(var + 7, "TNS")) {
    01071             /* CALLINGTNS */
    01072             snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
    01073             *ret = workspace;
    01074          } else
    01075             goto icky;
    01076       } else
    01077          goto icky;
    01078    } else if (c && !strcmp(var, "DNID")) {
    01079       if (c->cid.cid_dnid) {
    01080          ast_copy_string(workspace, c->cid.cid_dnid, workspacelen);
    01081          *ret = workspace;
    01082       } else
    01083          *ret = NULL;
    01084    } else if (c && !strcmp(var, "HINT")) {
    01085       if (!ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten))
    01086          *ret = NULL;
    01087       else
    01088          *ret = workspace;
    01089    } else if (c && !strcmp(var, "HINTNAME")) {
    01090       if (!ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten))
    01091          *ret = NULL;
    01092       else
    01093          *ret = workspace;
    01094    } else if (c && !strcmp(var, "EXTEN")) {
    01095       ast_copy_string(workspace, c->exten, workspacelen);
    01096       *ret = workspace;
    01097    } else if (c && !strcmp(var, "RDNIS")) {
    01098       if (c->cid.cid_rdnis) {
    01099          ast_copy_string(workspace, c->cid.cid_rdnis, workspacelen);
    01100          *ret = workspace;
    01101       } else
    01102          *ret = NULL;
    01103    } else if (c && !strcmp(var, "CONTEXT")) {
    01104       ast_copy_string(workspace, c->context, workspacelen);
    01105       *ret = workspace;
    01106    } else if (c && !strcmp(var, "PRIORITY")) {
    01107       snprintf(workspace, workspacelen, "%d", c->priority);
    01108       *ret = workspace;
    01109    } else if (c && !strcmp(var, "CHANNEL")) {
    01110       ast_copy_string(workspace, c->name, workspacelen);
    01111       *ret = workspace;
    01112    } else if (!strcmp(var, "EPOCH")) {
    01113       snprintf(workspace, workspacelen, "%u",(int)time(NULL));
    01114       *ret = workspace;
    01115    } else if (!strcmp(var, "DATETIME")) {
    01116       thistime=time(NULL);
    01117       localtime_r(&thistime, &brokentime);
    01118       snprintf(workspace, workspacelen, "%02d%02d%04d-%02d:%02d:%02d",
    01119          brokentime.tm_mday,
    01120          brokentime.tm_mon+1,
    01121          brokentime.tm_year+1900,
    01122          brokentime.tm_hour,
    01123          brokentime.tm_min,
    01124          brokentime.tm_sec
    01125       );
    01126       *ret = workspace;
    01127    } else if (!strcmp(var, "TIMESTAMP")) {
    01128       thistime=time(NULL);
    01129       localtime_r(&thistime, &brokentime);
    01130       /* 20031130-150612 */
    01131       snprintf(workspace, workspacelen, "%04d%02d%02d-%02d%02d%02d",
    01132          brokentime.tm_year+1900,
    01133          brokentime.tm_mon+1,
    01134          brokentime.tm_mday,
    01135          brokentime.tm_hour,
    01136          brokentime.tm_min,
    01137          brokentime.tm_sec
    01138       );
    01139       *ret = workspace;
    01140    } else if (c && !strcmp(var, "UNIQUEID")) {
    01141       snprintf(workspace, workspacelen, "%s", c->uniqueid);
    01142       *ret = workspace;
    01143    } else if (c && !strcmp(var, "HANGUPCAUSE")) {
    01144       snprintf(workspace, workspacelen, "%d", c->hangupcause);
    01145       *ret = workspace;
    01146    } else if (c && !strcmp(var, "ACCOUNTCODE")) {
    01147       ast_copy_string(workspace, c->accountcode, workspacelen);
    01148       *ret = workspace;
    01149    } else if (c && !strcmp(var, "LANGUAGE")) {
    01150       ast_copy_string(workspace, c->language, workspacelen);
    01151       *ret = workspace;
    01152    } else {
    01153 icky:
    01154       if (headp) {
    01155          AST_LIST_TRAVERSE(headp,variables,entries) {
    01156 #if 0
    01157             ast_log(LOG_WARNING,"Comparing variable '%s' with '%s'\n",var,ast_var_name(variables));
    01158 #endif
    01159             if (strcasecmp(ast_var_name(variables),var)==0) {
    01160                *ret=ast_var_value(variables);
    01161                if (*ret) {
    01162                   ast_copy_string(workspace, *ret, workspacelen);
    01163                   *ret = workspace;
    01164                }
    01165                break;
    01166             }
    01167          }
    01168       }
    01169       if (!(*ret)) {
    01170          /* Try globals */
    01171          ast_mutex_lock(&globalslock);
    01172          AST_LIST_TRAVERSE(&globals,variables,entries) {
    01173             if (strcasecmp(ast_var_name(variables),var)==0) {
    01174                *ret = ast_var_value(variables);
    01175                if (*ret) {
    01176                   ast_copy_string(workspace, *ret, workspacelen);
    01177                   *ret = workspace;
    01178                }
    01179             }
    01180          }
    01181          ast_mutex_unlock(&globalslock);
    01182       }
    01183    }
    01184 }
    01185
    01186 /*! \brief CLI function to show installed custom functions
    01187     \addtogroup CLI_functions
    01188  */
    01189 static int handle_show_functions(int fd, int argc, char *argv[])
    01190 {
    01191    struct ast_custom_function *acf;
    01192    int count_acf = 0;
    01193
    01194    ast_cli(fd, "Installed Custom Functions:\n--------------------------------------------------------------------------------\n");
    01195    ast_mutex_lock(&acflock);
    01196    for (acf = acf_root ; acf; acf = acf->next) {
    01197       ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
    01198       count_acf++;
    01199    }
    01200    ast_mutex_unlock(&acflock);
    01201    ast_cli(fd, "%d custom functions installed.\n", count_acf);
    01202    return 0;
    01203 }
    01204
    01205 static int handle_show_function(int fd, int argc, char *argv[])
    01206 {
    01207    struct ast_custom_function *acf;
    01208    /* Maximum number of characters added by terminal coloring is 22 */
    01209    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
    01210    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
    01211    char stxtitle[40], *syntax = NULL;
    01212    int synopsis_size, description_size, syntax_size;
    01213
    01214    if (argc < 3) return RESULT_SHOWUSAGE;
    01215
    01216    if (!(acf = ast_custom_function_find(argv[2]))) {
    01217       ast_cli(fd, "No function by that name registered.\n");
    01218       return RESULT_FAILURE;
    01219
    01220    }
    01221
    01222    if (acf->synopsis)
    01223       synopsis_size = strlen(acf->synopsis) + 23;
    01224    else
    01225       synopsis_size = strlen("Not available") + 23;
    01226    synopsis = alloca(synopsis_size);
    01227
    01228    if (acf->desc)
    01229       description_size = strlen(acf->desc) + 23;
    01230    else
    01231       description_size = strlen("Not available") + 23;
    01232    description = alloca(description_size);
    01233
    01234    if (acf->syntax)
    01235       syntax_size = strlen(acf->syntax) + 23;
    01236    else
    01237       syntax_size = strlen("Not available") + 23;
    01238    syntax = alloca(syntax_size);
    01239
    01240    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
    01241    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
    01242    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
    01243    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
    01244    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
    01245    term_color(syntax,
    01246          acf->syntax ? acf->syntax : "Not available",
    01247          COLOR_CYAN, 0, syntax_size);
    01248    term_color(synopsis,
    01249          acf->synopsis ? acf->synopsis : "Not available",
    01250          COLOR_CYAN, 0, synopsis_size);
    01251    term_color(description,
    01252          acf->desc ? acf->desc : "Not available",
    01253          COLOR_CYAN, 0, description_size);
    01254
    01255    ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
    01256
    01257    return RESULT_SUCCESS;
    01258 }
    01259
    01260 static char *complete_show_function(char *line, char *word, int pos, int state)
    01261 {
    01262    struct ast_custom_function *acf;
    01263    int which = 0;
    01264
    01265    /* try to lock functions list ... */
    01266    if (ast_mutex_lock(&acflock)) {
    01267       ast_log(LOG_ERROR, "Unable to lock function list\n");
    01268       return NULL;
    01269    }
    01270
    01271    acf = acf_root;
    01272    while (acf) {
    01273       if (!strncasecmp(word, acf->name, strlen(word))) {
    01274          if (++which > state) {
    01275             char *ret = strdup(acf->name);
    01276             ast_mutex_unlock(&acflock);
    01277             return ret;
    01278          }
    01279       }
    01280       acf = acf->next;
    01281    }
    01282
    01283    ast_mutex_unlock(&acflock);
    01284    return NULL;
    01285 }
    01286
    01287 struct ast_custom_function* ast_custom_function_find(char *name)
    01288 {
    01289    struct ast_custom_function *acfptr;
    01290
    01291    /* try to lock functions list ... */
    01292    if (ast_mutex_lock(&acflock)) {
    01293       ast_log(LOG_ERROR, "Unable to lock function list\n");
    01294       return NULL;
    01295    }
    01296
    01297    for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
    01298       if (!strcmp(name, acfptr->name)) {
    01299          break;
    01300       }
    01301    }
    01302
    01303    ast_mutex_unlock(&acflock);
    01304
    01305    return acfptr;
    01306 }
    01307
    01308 int ast_custom_function_unregister(struct ast_custom_function *acf)
    01309 {
    01310    struct ast_custom_function *acfptr, *lastacf = NULL;
    01311    int res = -1;
    01312
    01313    if (!acf)
    01314       return -1;
    01315
    01316    /* try to lock functions list ... */
    01317    if (ast_mutex_lock(&acflock)) {
    01318       ast_log(LOG_ERROR, "Unable to lock function list\n");
    01319       return -1;
    01320    }
    01321
    01322    for (acfptr = acf_root; acfptr; acfptr = acfptr->next) {
    01323       if (acfptr == acf) {
    01324          if (lastacf) {
    01325             lastacf->next = acf->next;
    01326          } else {
    01327             acf_root = acf->next;
    01328          }
    01329          res = 0;
    01330          break;
    01331       }
    01332       lastacf = acfptr;
    01333    }
    01334
    01335    ast_mutex_unlock(&acflock);
    01336
    01337    if (!res && (option_verbose > 1))
    01338       ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
    01339
    01340    return res;
    01341 }
    01342
    01343 int ast_custom_function_register(struct ast_custom_function *acf)
    01344 {
    01345    if (!acf)
    01346       return -1;
    01347
    01348    /* try to lock functions list ... */
    01349    if (ast_mutex_lock(&acflock)) {
    01350       ast_log(LOG_ERROR, "Unable to lock function list. Failed registering function %s\n", acf->name);
    01351       return -1;
    01352    }
    01353
    01354    if (ast_custom_function_find(acf->name)) {
    01355       ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
    01356       ast_mutex_unlock(&acflock);
    01357       return -1;
    01358    }
    01359
    01360    acf->next = acf_root;
    01361    acf_root = acf;
    01362
    01363    ast_mutex_unlock(&acflock);
    01364
    01365    if (option_verbose > 1)
    01366       ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
    01367
    01368    return 0;
    01369 }
    01370
    01371 char *ast_func_read(struct ast_channel *chan, const char *in, char *workspace, size_t len)
    01372 {
    01373    char *args = NULL, *function, *p;
    01374    char *ret = "0";
    01375    struct ast_custom_function *acfptr;
    01376
    01377    function = ast_strdupa(in);
    01378    if (!function) {
    01379       ast_log(LOG_ERROR, "Out of memory\n");
    01380       return ret;
    01381    }
    01382    if ((args = strchr(function, '('))) {
    01383       *args = '\0';
    01384       args++;
    01385       if ((p = strrchr(args, ')'))) {
    01386          *p = '\0';
    01387       } else {
    01388          ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
    01389       }
    01390    } else {
    01391       ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
    01392    }
    01393
    01394    if ((acfptr = ast_custom_function_find(function))) {
    01395       /* run the custom function */
    01396       if (acfptr->read) {
    01397          return acfptr->read(chan, function, args, workspace, len);
    01398       } else {
    01399          ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
    01400       }
    01401    } else {
    01402       ast_log(LOG_ERROR, "Function %s not registered\n", function);
    01403    }
    01404    return ret;
    01405 }
    01406
    01407 void ast_func_write(struct ast_channel *chan, const char *in, const char *value)
    01408 {
    01409    char *args = NULL, *function, *p;
    01410    struct ast_custom_function *acfptr;
    01411
    01412    function = ast_strdupa(in);
    01413    if (!function) {
    01414       ast_log(LOG_ERROR, "Out of memory\n");
    01415       return;
    01416    }
    01417    if ((args = strchr(function, '('))) {
    01418       *args = '\0';
    01419       args++;
    01420       if ((p = strrchr(args, ')'))) {
    01421          *p = '\0';
    01422       } else {
    01423          ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
    01424       }
    01425    } else {
    01426       ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
    01427    }
    01428
    01429    if ((acfptr = ast_custom_function_find(function))) {
    01430       /* run the custom function */
    01431       if (acfptr->write) {
    01432          acfptr->write(chan, function, args, value);
    01433       } else {
    01434          ast_log(LOG_ERROR, "Function %s is read-only, it cannot be written to\n", function);
    01435       }
    01436    } else {
    01437       ast_log(LOG_ERROR, "Function %s not registered\n", function);
    01438    }
    01439 }
    01440
    01441 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
    01442 {
    01443    char *cp4;
    01444    const char *tmp, *whereweare;
    01445    int length, offset, offset2, isfunction;
    01446    char *workspace = NULL;
    01447    char *ltmp = NULL, *var = NULL;
    01448    char *nextvar, *nextexp, *nextthing;
    01449    char *vars, *vare;
    01450    int pos, brackets, needsub, len;
    01451
    01452    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
    01453       zero-filled */
    01454    whereweare=tmp=cp1;
    01455    while(!ast_strlen_zero(whereweare) && count) {
    01456       /* Assume we're copying the whole remaining string */
    01457       pos = strlen(whereweare);
    01458       nextvar = NULL;
    01459       nextexp = NULL;
    01460       nextthing = strchr(whereweare, '$');
    01461       if (nextthing) {
    01462          switch(nextthing[1]) {
    01463          case '{':
    01464             nextvar = nextthing;
    01465             pos = nextvar - whereweare;
    01466             break;
    01467          case '[':
    01468             nextexp = nextthing;
    01469             pos = nextexp - whereweare;
    01470             break;
    01471          }
    01472       }
    01473
    01474       if (pos) {
    01475          /* Can't copy more than 'count' bytes */
    01476          if (pos > count)
    01477             pos = count;
    01478
    01479          /* Copy that many bytes */
    01480          memcpy(cp2, whereweare, pos);
    01481
    01482          count -= pos;
    01483          cp2 += pos;
    01484          whereweare += pos;
    01485       }
    01486
    01487       if (nextvar) {
    01488          /* We have a variable.  Find the start and end, and determine
    01489             if we are going to have to recursively call ourselves on the
    01490             contents */
    01491          vars = vare = nextvar + 2;
    01492          brackets = 1;
    01493          needsub = 0;
    01494
    01495          /* Find the end of it */
    01496          while (brackets && *vare) {
    01497             if ((vare[0] == '$') && (vare[1] == '{')) {
    01498                needsub++;
    01499             } else if (vare[0] == '{') {
    01500                brackets++;
    01501             } else if (vare[0] == '}') {
    01502                brackets--;
    01503             } else if ((vare[0] == '$') && (vare[1] == '['))
    01504                needsub++;
    01505             vare++;
    01506          }
    01507          if (brackets)
    01508             ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
    01509          len = vare - vars - 1;
    01510
    01511          /* Skip totally over variable string */
    01512          whereweare += (len + 3);
    01513
    01514          if (!var)
    01515             var = alloca(VAR_BUF_SIZE);
    01516
    01517          /* Store variable name (and truncate) */
    01518          ast_copy_string(var, vars, len + 1);
    01519
    01520          /* Substitute if necessary */
    01521          if (needsub) {
    01522             if (!ltmp)
    01523                ltmp = alloca(VAR_BUF_SIZE);
    01524
    01525             memset(ltmp, 0, VAR_BUF_SIZE);
    01526             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
    01527             vars = ltmp;
    01528          } else {
    01529             vars = var;
    01530          }
    01531
    01532          if (!workspace)
    01533             workspace = alloca(VAR_BUF_SIZE);
    01534
    01535          workspace[0] = '\0';
    01536
    01537          parse_variable_name(vars, &offset, &offset2, &isfunction);
    01538          if (isfunction) {
    01539             /* Evaluate function */
    01540             cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE);
    01541
    01542             ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
    01543          } else {
    01544             /* Retrieve variable value */
    01545             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
    01546          }
    01547          if (cp4) {
    01548             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
    01549
    01550             length = strlen(cp4);
    01551             if (length > count)
    01552                length = count;
    01553             memcpy(cp2, cp4, length);
    01554             count -= length;
    01555             cp2 += length;
    01556          }
    01557       } else if (nextexp) {
    01558          /* We have an expression.  Find the start and end, and determine
    01559             if we are going to have to recursively call ourselves on the
    01560             contents */
    01561          vars = vare = nextexp + 2;
    01562          brackets = 1;
    01563          needsub = 0;
    01564
    01565          /* Find the end of it */
    01566          while(brackets && *vare) {
    01567             if ((vare[0] == '$') && (vare[1] == '[')) {
    01568                needsub++;
    01569                brackets++;
    01570                vare++;
    01571             } else if (vare[0] == '[') {
    01572                brackets++;
    01573             } else if (vare[0] == ']') {
    01574                brackets--;
    01575             } else if ((vare[0] == '$') && (vare[1] == '{')) {
    01576                needsub++;
    01577                vare++;
    01578             }
    01579             vare++;
    01580          }
    01581          if (brackets)
    01582             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
    01583          len = vare - vars - 1;
    01584
    01585          /* Skip totally over expression */
    01586          whereweare += (len + 3);
    01587
    01588          if (!var)
    01589             var = alloca(VAR_BUF_SIZE);
    01590
    01591          /* Store variable name (and truncate) */
    01592          ast_copy_string(var, vars, len + 1);
    01593
    01594          /* Substitute if necessary */
    01595          if (needsub) {
    01596             if (!ltmp)
    01597                ltmp = alloca(VAR_BUF_SIZE);
    01598
    01599             memset(ltmp, 0, VAR_BUF_SIZE);
    01600             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
    01601             vars = ltmp;
    01602          } else {
    01603             vars = var;
    01604          }
    01605
    01606          length = ast_expr(vars, cp2, count);
    01607
    01608          if (length) {
    01609             ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
    01610             count -= length;
    01611             cp2 += length;
    01612          }
    01613       } else
    01614          break;
    01615    }
    01616 }
    01617
    01618 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
    01619 {
    01620    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
    01621 }
    01622
    01623 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
    01624 {
    01625    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
    01626 }
    01627
    01628 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
    01629 {
    01630    memset(passdata, 0, datalen);
    01631
    01632    /* No variables or expressions in e->data, so why scan it? */
    01633    if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
    01634       ast_copy_string(passdata, e->data, datalen);
    01635       return;
    01636    }
    01637
    01638    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
    01639 }
    01640
    01641 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
    01642 {
    01643    struct ast_exten *e;
    01644    struct ast_app *app;
    01645    struct ast_switch *sw;
    01646    char *data;
    01647    const char *foundcontext=NULL;
    01648    int newstack = 0;
    01649    int res;
    01650    int status = 0;
    01651    char *incstack[AST_PBX_MAX_STACK];
    01652    char passdata[EXT_DATA_SIZE];
    01653    int stacklen = 0;
    01654    char tmp[80];
    01655    char tmp2[80];
    01656    char tmp3[EXT_DATA_SIZE];
    01657    char atmp[80];
    01658    char atmp2[EXT_DATA_SIZE+100];
    01659
    01660    if (ast_mutex_lock(&conlock)) {
    01661       ast_log(LOG_WARNING, "Unable to obtain lock\n");
    01662       if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH) || (action == HELPER_MATCHMORE))
    01663          return 0;
    01664       else
    01665          return -1;
    01666    }
    01667    e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
    01668    if (e) {
    01669       switch(action) {
    01670       case HELPER_CANMATCH:
    01671          ast_mutex_unlock(&conlock);
    01672          return -1;
    01673       case HELPER_EXISTS:
    01674          ast_mutex_unlock(&conlock);
    01675          return -1;
    01676       case HELPER_FINDLABEL:
    01677          res = e->priority;
    01678          ast_mutex_unlock(&conlock);
    01679          return res;
    01680       case HELPER_MATCHMORE:
    01681          ast_mutex_unlock(&conlock);
    01682          return -1;
    01683       case HELPER_SPAWN:
    01684          newstack++;
    01685          /* Fall through */
    01686       case HELPER_EXEC:
    01687          app = pbx_findapp(e->app);
    01688          ast_mutex_unlock(&conlock);
    01689          if (app) {
    01690             if (c->context != context)
    01691                ast_copy_string(c->context, context, sizeof(c->context));
    01692             if (c->exten != exten)
    01693                ast_copy_string(c->exten, exten, sizeof(c->exten));
    01694             c->priority = priority;
    01695             pbx_substitute_variables(passdata, sizeof(passdata), c, e);
    01696             if (option_debug) {
    01697                   ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
    01698                   snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
    01699                   snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), (newstack ? "in new stack" : "in same stack"));
    01700                   pbx_builtin_setvar_helper(c, atmp, atmp2);
    01701             }
    01702             if (option_verbose > 2)
    01703                   ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
    01704                         term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
    01705                         term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
    01706                         term_color(tmp3, (!ast_strlen_zero(passdata) ? (char *)passdata : ""), COLOR_BRMAGENTA, 0, sizeof(tmp3)),
    01707                         (newstack ? "in new stack" : "in same stack"));
    01708             manager_event(EVENT_FLAG_CALL, "Newexten",
    01709                "Channel: %s\r\n"
    01710                "Context: %s\r\n"
    01711                "Extension: %s\r\n"
    01712                "Priority: %d\r\n"
    01713                "Application: %s\r\n"
    01714                "AppData: %s\r\n"
    01715                "Uniqueid: %s\r\n",
    01716                c->name, c->context, c->exten, c->priority, app->name, passdata ? passdata : "(NULL)", c->uniqueid);
    01717             res = pbx_exec(c, app, passdata, newstack);
    01718             return res;
    01719          } else {
    01720             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
    01721             return -1;
    01722          }
    01723       default:
    01724          ast_log(LOG_WARNING, "Huh (%d)?\n", action);       return -1;
    01725       }
    01726    } else if (sw) {
    01727       switch(action) {
    01728       case HELPER_CANMATCH:
    01729          ast_mutex_unlock(&conlock);
    01730          return -1;
    01731       case HELPER_EXISTS:
    01732          ast_mutex_unlock(&conlock);
    01733          return -1;
    01734       case HELPER_MATCHMORE:
    01735          ast_mutex_unlock(&conlock);
    01736          return -1;
    01737       case HELPER_FINDLABEL:
    01738          ast_mutex_unlock(&conlock);
    01739          return -1;
    01740       case HELPER_SPAWN:
    01741          newstack++;
    01742          /* Fall through */
    01743       case HELPER_EXEC:
    01744          ast_mutex_unlock(&conlock);
    01745          if (sw->exec)
    01746             res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, newstack, data);
    01747          else {
    01748             ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
    01749             res = -1;
    01750          }
    01751          return res;
    01752       default:
    01753          ast_log(LOG_WARNING, "Huh (%d)?\n", action);
    01754          return -1;
    01755       }
    01756    } else {
    01757       ast_mutex_unlock(&conlock);
    01758       switch(status) {
    01759       case STATUS_NO_CONTEXT:
    01760          if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
    01761             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
    01762          break;
    01763       case STATUS_NO_EXTENSION:
    01764          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
    01765             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
    01766          break;
    01767       case STATUS_NO_PRIORITY:
    01768          if ((action != HELPER_EXISTS) && (action !=  HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
    01769             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
    01770          break;
    01771       case STATUS_NO_LABEL:
    01772          if (context)
    01773             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
    01774          break;
    01775       default:
    01776          ast_log(LOG_DEBUG, "Shouldn't happen!\n");
    01777       }
    01778
    01779       if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
    01780          return -1;
    01781       else
    01782          return 0;
    01783    }
    01784
    01785 }
    01786
    01787 /*! \brief  ast_hint_extension: Find hint for given extension in context */
    01788 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
    01789 {
    01790    struct ast_exten *e;
    01791    struct ast_switch *sw;
    01792    char *data;
    01793    const char *foundcontext = NULL;
    01794    int status = 0;
    01795    char *incstack[AST_PBX_MAX_STACK];
    01796    int stacklen = 0;
    01797
    01798    if (ast_mutex_lock(&conlock)) {
    01799       ast_log(LOG_WARNING, "Unable to obtain lock\n");
    01800       return NULL;
    01801    }
    01802    e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
    01803    ast_mutex_unlock(&conlock);
    01804    return e;
    01805 }
    01806
    01807 /*! \brief  ast_extensions_state2: Check state of extension by using hints */
    01808 static int ast_extension_state2(struct ast_exten *e)
    01809 {
    01810    char hint[AST_MAX_EXTENSION] = "";
    01811    char *cur, *rest;
    01812    int res = -1;
    01813    int allunavailable = 1, allbusy = 1, allfree = 1;
    01814    int busy = 0, inuse = 0, ring = 0;
    01815
    01816    if (!e)
    01817       return -1;
    01818
    01819    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
    01820
    01821    cur = hint;       /* On or more devices separated with a & character */
    01822    do {
    01823       rest = strchr(cur, '&');
    01824       if (rest) {
    01825          *rest = 0;
    01826          rest++;
    01827       }
    01828
    01829       res = ast_device_state(cur);
    01830       switch (res) {
    01831       case AST_DEVICE_NOT_INUSE:
    01832          allunavailable = 0;
    01833          allbusy = 0;
    01834          break;
    01835       case AST_DEVICE_INUSE:
    01836          inuse = 1;
    01837          allunavailable = 0;
    01838          allfree = 0;
    01839          break;
    01840       case AST_DEVICE_RINGING:
    01841          ring = 1;
    01842          allunavailable = 0;
    01843          allfree = 0;
    01844          break;
    01845       case AST_DEVICE_BUSY:
    01846          allunavailable = 0;
    01847          allfree = 0;
    01848          busy = 1;
    01849          break;
    01850       case AST_DEVICE_UNAVAILABLE:
    01851       case AST_DEVICE_INVALID:
    01852          allbusy = 0;
    01853          allfree = 0;
    01854          break;
    01855       default:
    01856          allunavailable = 0;
    01857          allbusy = 0;
    01858          allfree = 0;
    01859       }
    01860       cur = rest;
    01861    } while (cur);
    01862
    01863    if (!inuse && ring)
    01864       return AST_EXTENSION_RINGING;
    01865    if (inuse && ring)
    01866       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
    01867    if (inuse)
    01868       return AST_EXTENSION_INUSE;
    01869    if (allfree)
    01870       return AST_EXTENSION_NOT_INUSE;
    01871    if (allbusy)
    01872       return AST_EXTENSION_BUSY;
    01873    if (allunavailable)
    01874       return AST_EXTENSION_UNAVAILABLE;
    01875    if (busy)
    01876       return AST_EXTENSION_INUSE;
    01877
    01878    return AST_EXTENSION_NOT_INUSE;
    01879 }
    01880
    01881 /*! \brief  ast_extension_state2str: Return extension_state as string */
    01882 const char *ast_extension_state2str(int extension_state)
    01883 {
    01884    int i;
    01885
    01886    for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
    01887       if (extension_states[i].extension_state == extension_state) {
    01888          return extension_states[i].text;
    01889       }
    01890    }
    01891    return "Unknown";
    01892 }
    01893
    01894 /*! \brief  ast_extension_state: Check extension state for an extension by using hint */
    01895 int ast_extension_state(struct ast_channel *c, char *context, char *exten)
    01896 {
    01897    struct ast_exten *e;
    01898
    01899    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
    01900    if (!e)
    01901       return -1;           /* No hint, return -1 */
    01902
    01903    return ast_extension_state2(e);        /* Check all devices in the hint */
    01904 }
    01905
    01906 void ast_hint_state_changed(const char *device)
    01907 {
    01908    struct ast_hint *hint;
    01909    struct ast_state_cb *cblist;
    01910    char buf[AST_MAX_EXTENSION];
    01911    char *parse;
    01912    char *cur;
    01913    int state;
    01914
    01915    ast_mutex_lock(&hintlock);
    01916
    01917    for (hint = hints; hint; hint = hint->next) {
    01918       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
    01919       parse = buf;
    01920       for (cur = strsep(&parse, "&"); cur; cur = strsep(&parse, "&")) {
    01921          if (strcasecmp(cur, device))
    01922             continue;
    01923
    01924          /* Get device state for this hint */
    01925          state = ast_extension_state2(hint->exten);
    01926
    01927          if ((state == -1) || (state == hint->laststate))
    01928             continue;
    01929
    01930          /* Device state changed since last check - notify the watchers */
    01931
    01932          /* For general callbacks */
    01933          for (cblist = statecbs; cblist; cblist = cblist->next)
    01934             cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
    01935
    01936          /* For extension callbacks */
    01937          for (cblist = hint->callbacks; cblist; cblist = cblist->next)
    01938             cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
    01939
    01940          hint->laststate = state;
    01941          break;
    01942       }
    01943    }
    01944
    01945    ast_mutex_unlock(&hintlock);
    01946 }
    01947
    01948 /*! \brief  ast_extension_state_add: Add watcher for extension states */
    01949 int ast_extension_state_add(const char *context, const char *exten,
    01950              ast_state_cb_type callback, void *data)
    01951 {
    01952    struct ast_hint *list;
    01953    struct ast_state_cb *cblist;
    01954    struct ast_exten *e;
    01955
    01956    /* If there's no context and extension:  add callback to statecbs list */
    01957    if (!context && !exten) {
    01958       ast_mutex_lock(&hintlock);
    01959
    01960       cblist = statecbs;
    01961       while (cblist) {
    01962          if (cblist->callback == callback) {
    01963             cblist->data = data;
    01964             ast_mutex_unlock(&hintlock);
    01965             return 0;
    01966          }
    01967          cblist = cblist->next;
    01968       }
    01969
    01970       /* Now insert the callback */
    01971       cblist = malloc(sizeof(struct ast_state_cb));
    01972       if (!cblist) {
    01973          ast_mutex_unlock(&hintlock);
    01974          return -1;
    01975       }
    01976       memset(cblist, 0, sizeof(struct ast_state_cb));
    01977       cblist->id = 0;
    01978       cblist->callback = callback;
    01979       cblist->data = data;
    01980
    01981       cblist->next = statecbs;
    01982       statecbs = cblist;
    01983
    01984       ast_mutex_unlock(&hintlock);
    01985       return 0;
    01986    }
    01987
    01988    if (!context || !exten)
    01989       return -1;
    01990
    01991    /* This callback type is for only one hint, so get the hint */
    01992    e = ast_hint_extension(NULL, context, exten);
    01993    if (!e) {
    01994       return -1;
    01995    }
    01996
    01997    /* Find the hint in the list of hints */
    01998    ast_mutex_lock(&hintlock);
    01999    list = hints;
    02000
    02001    while (list) {
    02002       if (list->exten == e)
    02003          break;
    02004       list = list->next;
    02005    }
    02006
    02007    if (!list) {
    02008       /* We have no hint, sorry */
    02009       ast_mutex_unlock(&hintlock);
    02010       return -1;
    02011    }
    02012
    02013    /* Now insert the callback in the callback list  */
    02014    cblist = malloc(sizeof(struct ast_state_cb));
    02015    if (!cblist) {
    02016       ast_mutex_unlock(&hintlock);
    02017       return -1;
    02018    }
    02019    memset(cblist, 0, sizeof(struct ast_state_cb));
    02020    cblist->id = stateid++;    /* Unique ID for this callback */
    02021    cblist->callback = callback;  /* Pointer to callback routine */
    02022    cblist->data = data;    /* Data for the callback */
    02023
    02024    cblist->next = list->callbacks;
    02025    list->callbacks = cblist;
    02026
    02027    ast_mutex_unlock(&hintlock);
    02028    return cblist->id;
    02029 }
    02030
    02031 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
    02032 int ast_extension_state_del(int id, ast_state_cb_type callback)
    02033 {
    02034    struct ast_hint *list;
    02035    struct ast_state_cb *cblist, *cbprev;
    02036
    02037    if (!id && !callback)
    02038       return -1;
    02039
    02040    ast_mutex_lock(&hintlock);
    02041
    02042    /* id is zero is a callback without extension */
    02043    if (!id) {
    02044       cbprev = NULL;
    02045       cblist = statecbs;
    02046       while (cblist) {
    02047          if (cblist->callback == callback) {
    02048             if (!cbprev)
    02049                   statecbs = cblist->next;
    02050             else
    02051                   cbprev->next = cblist->next;
    02052
    02053             free(cblist);
    02054
    02055                ast_mutex_unlock(&hintlock);
    02056             return 0;
    02057             }
    02058             cbprev = cblist;
    02059             cblist = cblist->next;
    02060       }
    02061
    02062       ast_mutex_unlock(&hintlock);
    02063       return -1;
    02064    }
    02065
    02066    /* id greater than zero is a callback with extension */
    02067    /* Find the callback based on ID */
    02068    list = hints;
    02069    while (list) {
    02070       cblist = list->callbacks;
    02071       cbprev = NULL;
    02072       while (cblist) {
    02073             if (cblist->id==id) {
    02074             if (!cbprev)
    02075                   list->callbacks = cblist->next;
    02076             else
    02077                   cbprev->next = cblist->next;
    02078
    02079             free(cblist);
    02080
    02081             ast_mutex_unlock(&hintlock);
    02082             return 0;
    02083             }
    02084             cbprev = cblist;
    02085             cblist = cblist->next;
    02086       }
    02087       list = list->next;
    02088    }
    02089
    02090    ast_mutex_unlock(&hintlock);
    02091    return -1;
    02092 }
    02093
    02094 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
    02095 static int ast_add_hint(struct ast_exten *e)
    02096 {
    02097    struct ast_hint *list;
    02098
    02099    if (!e)
    02100       return -1;
    02101
    02102    ast_mutex_lock(&hintlock);
    02103    list = hints;
    02104
    02105    /* Search if hint exists, do nothing */
    02106    while (list) {
    02107       if (list->exten == e) {
    02108          ast_mutex_unlock(&hintlock);
    02109          if (option_debug > 1)
    02110             ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
    02111          return -1;
    02112       }
    02113       list = list->next;
    02114    }
    02115
    02116    if (option_debug > 1)
    02117       ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
    02118
    02119    list = malloc(sizeof(struct ast_hint));
    02120    if (!list) {
    02121       ast_mutex_unlock(&hintlock);
    02122       if (option_debug > 1)
    02123          ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
    02124       return -1;
    02125    }
    02126    /* Initialize and insert new item at the top */
    02127    memset(list, 0, sizeof(struct ast_hint));
    02128    list->exten = e;
    02129    list->laststate = ast_extension_state2(e);
    02130    list->next = hints;
    02131    hints = list;
    02132
    02133    ast_mutex_unlock(&hintlock);
    02134    return 0;
    02135 }
    02136
    02137 /*! \brief  ast_change_hint: Change hint for an extension */
    02138 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
    02139 {
    02140    struct ast_hint *list;
    02141
    02142    ast_mutex_lock(&hintlock);
    02143    list = hints;
    02144
    02145    while(list) {
    02146       if (list->exten == oe) {
    02147             list->exten = ne;
    02148          ast_mutex_unlock(&hintlock);
    02149          return 0;
    02150       }
    02151       list = list->next;
    02152    }
    02153    ast_mutex_unlock(&hintlock);
    02154
    02155    return -1;
    02156 }
    02157
    02158 /*! \brief  ast_remove_hint: Remove hint from extension */
    02159 static int ast_remove_hint(struct ast_exten *e)
    02160 {
    02161    /* Cleanup the Notifys if hint is removed */
    02162    struct ast_hint *list, *prev = NULL;
    02163    struct ast_state_cb *cblist, *cbprev;
    02164
    02165    if (!e)
    02166       return -1;
    02167
    02168    ast_mutex_lock(&hintlock);
    02169
    02170    list = hints;
    02171    while(list) {
    02172       if (list->exten==e) {
    02173          cbprev = NULL;
    02174          cblist = list->callbacks;
    02175          while (cblist) {
    02176             /* Notify with -1 and remove all callbacks */
    02177             cbprev = cblist;
    02178             cblist = cblist->next;
    02179             cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
    02180             free(cbprev);
    02181             }
    02182             list->callbacks = NULL;
    02183
    02184             if (!prev)
    02185             hints = list->next;
    02186             else
    02187             prev->next = list->next;
    02188             free(list);
    02189
    02190          ast_mutex_unlock(&hintlock);
    02191          return 0;
    02192       } else {
    02193          prev = list;
    02194          list = list->next;
    02195       }
    02196    }
    02197
    02198    ast_mutex_unlock(&hintlock);
    02199    return -1;
    02200 }
    02201
    02202
    02203 /*! \brief  ast_get_hint: Get hint for channel */
    02204 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
    02205 {
    02206    struct ast_exten *e;
    02207    void *tmp;
    02208
    02209    e = ast_hint_extension(c, context, exten);
    02210    if (e) {
    02211       if (hint)
    02212           ast_copy_string(hint, ast_get_extension_app(e), hintsize);
    02213       if (name) {
    02214          tmp = ast_get_extension_app_data(e);
    02215          if (tmp)
    02216             ast_copy_string(name, (char *) tmp, namesize);
    02217       }
    02218        return -1;
    02219    }
    02220    return 0;
    02221 }
    02222
    02223 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
    02224 {
    02225    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
    02226 }
    02227
    02228 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
    02229 {
    02230    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
    02231 }
    02232
    02233 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
    02234 {
    02235    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
    02236 }
    02237
    02238 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
    02239 {
    02240    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
    02241 }
    02242
    02243 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
    02244 {
    02245    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
    02246 }
    02247
    02248 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
    02249 {
    02250    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
    02251 }
    02252
    02253 int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
    02254 {
    02255    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
    02256 }
    02257
    02258 static int __ast_pbx_run(struct ast_channel *c)
    02259 {
    02260    int firstpass = 1;
    02261    int digit;
    02262    char exten[256];
    02263    int pos;
    02264    int waittime;
    02265    int res=0;
    02266    int autoloopflag;
    02267
    02268    /* A little initial setup here */
    02269    if (c->pbx)
    02270       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
    02271    c->pbx = malloc(sizeof(struct ast_pbx));
    02272    if (!c->pbx) {
    02273       ast_log(LOG_ERROR, "Out of memory\n");
    02274       return -1;
    02275    }
    02276    if (c->amaflags) {
    02277       if (!c->cdr) {
    02278          c->cdr = ast_cdr_alloc();
    02279          if (!c->cdr) {
    02280             ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
    02281             free(c->pbx);
    02282             return -1;
    02283          }
    02284          ast_cdr_init(c->cdr, c);
    02285       }
    02286    }
    02287    memset(c->pbx, 0, sizeof(struct ast_pbx));
    02288    /* Set reasonable defaults */
    02289    c->pbx->rtimeout = 10;
    02290    c->pbx->dtimeout = 5;
    02291
    02292    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
    02293    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
    02294
    02295    /* Start by trying whatever the channel is set to */
    02296    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
    02297       /* If not successful fall back to 's' */
    02298       if (option_verbose > 1)
    02299          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);
    02300       ast_copy_string(c->exten, "s", sizeof(c->exten));
    02301       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
    02302          /* JK02: And finally back to default if everything else failed */
    02303          if (option_verbose > 1)
    02304             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);
    02305          ast_copy_string(c->context, "default", sizeof(c->context));
    02306       }
    02307       c->priority = 1;
    02308    }
    02309    if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
    02310       ast_cdr_start(c->cdr);
    02311    for(;;) {
    02312       pos = 0;
    02313       digit = 0;
    02314       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
    02315          memset(exten, 0, sizeof(exten));
    02316          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
    02317             /* Something bad happened, or a hangup has been requested. */
    02318             if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
    02319                (res == '*') || (res == '#')) {
    02320                ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
    02321                memset(exten, 0, sizeof(exten));
    02322                pos = 0;
    02323                exten[pos++] = digit = res;
    02324                break;
    02325             }
    02326             switch(res) {
    02327             case AST_PBX_KEEPALIVE:
    02328                if (option_debug)
    02329                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
    02330                if (option_verbose > 1)
    02331                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
    02332                goto out;
    02333                break;
    02334             default:
    02335                if (option_debug)
    02336                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
    02337                if (option_verbose > 1)
    02338                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
    02339                if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
    02340                   c->_softhangup =0;
    02341                   break;
    02342                }
    02343                /* atimeout */
    02344                if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
    02345                   break;
    02346                }
    02347
    02348                if (c->cdr) {
    02349                   ast_cdr_update(c);
    02350                }
    02351                goto out;
    02352             }
    02353          }
    02354          if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
    02355             ast_copy_string(c->exten, "T", sizeof(c->exten));
    02356             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
    02357             c->whentohangup = 0;
    02358             c->priority = 0;
    02359             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
    02360          } else if (c->_softhangup) {
    02361             ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
    02362                c->exten, c->priority);
    02363             goto out;
    02364          }
    02365          firstpass = 0;
    02366          c->priority++;
    02367       }
    02368       if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
    02369          /* It's not a valid extension anymore */
    02370          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
    02371             if (option_verbose > 2)
    02372                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
    02373             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
    02374             ast_copy_string(c->exten, "i", sizeof(c->exten));
    02375             c->priority = 1;
    02376          } else {
    02377             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
    02378                c->name, c->exten, c->context);
    02379             goto out;
    02380          }
    02381       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
    02382          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
    02383          c->_softhangup = 0;
    02384       } else {
    02385          /* Done, wait for an extension */
    02386          waittime = 0;
    02387          if (digit)
    02388             waittime = c->pbx->dtimeout;
    02389          else if (!autofallthrough)
    02390             waittime = c->pbx->rtimeout;
    02391          if (waittime) {
    02392             while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
    02393                /* As long as we're willing to wait, and as long as it's not defined,
    02394                   keep reading digits until we can't possibly get a right answer anymore.  */
    02395                digit = ast_waitfordigit(c, waittime * 1000);
    02396                if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
    02397                   c->_softhangup = 0;
    02398                } else {
    02399                   if (!digit)
    02400                      /* No entry */
    02401                      break;
    02402                   if (digit < 0)
    02403                      /* Error, maybe a  hangup */
    02404                      goto out;
    02405                   exten[pos++] = digit;
    02406                   waittime = c->pbx->dtimeout;
    02407                }
    02408             }
    02409             if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
    02410                /* Prepare the next cycle */
    02411                ast_copy_string(c->exten, exten, sizeof(c->exten));
    02412                c->priority = 1;
    02413             } else {
    02414                /* No such extension */
    02415                if (!ast_strlen_zero(exten)) {
    02416                   /* An invalid extension */
    02417                   if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
    02418                      if (option_verbose > 2)
    02419                         ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
    02420                      pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
    02421                      ast_copy_string(c->exten, "i", sizeof(c->exten));
    02422                      c->priority = 1;
    02423                   } else {
    02424                      ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
    02425                      goto out;
    02426                   }
    02427                } else {
    02428                   /* A simple timeout */
    02429                   if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
    02430                      if (option_verbose > 2)
    02431                         ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
    02432                      ast_copy_string(c->exten, "t", sizeof(c->exten));
    02433                      c->priority = 1;
    02434                   } else {
    02435                      ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
    02436                      goto out;
    02437                   }
    02438                }
    02439             }
    02440             if (c->cdr) {
    02441                if (option_verbose > 2)
    02442                   ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
    02443                ast_cdr_update(c);
    02444              }
    02445          } else {
    02446             char *status;
    02447
    02448             status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
    02449             if (!status)
    02450                status = "UNKNOWN";
    02451             if (option_verbose > 2)
    02452                ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
    02453             if (!strcasecmp(status, "CONGESTION"))
    02454                res = pbx_builtin_congestion(c, "10");
    02455             else if (!strcasecmp(status, "CHANUNAVAIL"))
    02456                res = pbx_builtin_congestion(c, "10");
    02457             else if (!strcasecmp(status, "BUSY"))
    02458                res = pbx_builtin_busy(c, "10");
    02459             goto out;
    02460          }
    02461       }
    02462    }
    02463    if (firstpass)
    02464       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
    02465 out:
    02466    if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
    02467       c->exten[0] = 'h';
    02468       c->exten[1] = '\0';
    02469       c->priority = 1;
    02470       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
    02471          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
    02472             /* Something bad happened, or a hangup has been requested. */
    02473             if (option_debug)
    02474                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
    02475             if (option_verbose > 1)
    02476                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
    02477             break;
    02478          }
    02479          c->priority++;
    02480       }
    02481    }
    02482    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
    02483
    02484    pbx_destroy(c->pbx);
    02485    c->pbx = NULL;
    02486    if (res != AST_PBX_KEEPALIVE)
    02487       ast_hangup(c);
    02488    return 0;
    02489 }
    02490
    02491 /* Returns 0 on success, non-zero if call limit was reached */
    02492 static int increase_call_count(const struct ast_channel *c)
    02493 {
    02494    int failed = 0;
    02495    double curloadavg;
    02496    ast_mutex_lock(&maxcalllock);
    02497    if (option_maxcalls) {
    02498       if (countcalls >= option_maxcalls) {
    02499          ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
    02500          failed = -1;
    02501       }
    02502    }
    02503    if (option_maxload) {
    02504       getloadavg(&curloadavg, 1);
    02505       if (curloadavg >= option_maxload) {
    02506          ast_log(LOG_NOTICE, "Maximum loadavg limit of %lf load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
    02507          failed = -1;
    02508       }
    02509    }
    02510    if (!failed)
    02511       countcalls++;
    02512    ast_mutex_unlock(&maxcalllock);
    02513
    02514    return failed;
    02515 }
    02516
    02517 static void decrease_call_count(void)
    02518 {
    02519    ast_mutex_lock(&maxcalllock);
    02520    if (countcalls > 0)
    02521       countcalls--;
    02522    ast_mutex_unlock(&maxcalllock);
    02523 }
    02524
    02525 static void *pbx_thread(void *data)
    02526 {
    02527    /* Oh joyeous kernel, we're a new thread, with nothing to do but
    02528       answer this channel and get it going.
    02529    */
    02530    /* NOTE:
    02531       The launcher of this function _MUST_ increment 'countcalls'
    02532       before invoking the function; it will be decremented when the
    02533       PBX has finished running on the channel
    02534     */
    02535    struct ast_channel *c = data;
    02536
    02537    __ast_pbx_run(c);
    02538    decrease_call_count();
    02539
    02540    pthread_exit(NULL);
    02541
    02542    return NULL;
    02543 }
    02544
    02545 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
    02546 {
    02547    pthread_t t;
    02548    pthread_attr_t attr;
    02549
    02550    if (!c) {
    02551       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
    02552       return AST_PBX_FAILED;
    02553    }
    02554
    02555    if (increase_call_count(c))
    02556       return AST_PBX_CALL_LIMIT;
    02557
    02558    /* Start a new thread, and get something handling this channel. */
    02559    pthread_attr_init(&attr);
    02560    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    02561    if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
    02562       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
    02563       pthread_attr_destroy(&attr);
    02564       return AST_PBX_FAILED;
    02565    }
    02566    pthread_attr_destroy(&attr);
    02567
    02568    return AST_PBX_SUCCESS;
    02569 }
    02570
    02571 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
    02572 {
    02573    enum ast_pbx_result res = AST_PBX_SUCCESS;
    02574
    02575    if (increase_call_count(c))
    02576       return AST_PBX_CALL_LIMIT;
    02577
    02578    res = __ast_pbx_run(c);
    02579    decrease_call_count();
    02580
    02581    return res;
    02582 }
    02583
    02584 int ast_active_calls(void)
    02585 {
    02586    return countcalls;
    02587 }
    02588
    02589 int pbx_set_autofallthrough(int newval)
    02590 {
    02591    int oldval;
    02592    oldval = autofallthrough;
    02593    if (oldval != newval)
    02594       autofallthrough = newval;
    02595    return oldval;
    02596 }
    02597
    02598 /*
    02599  * This function locks contexts list by &conlist, search for the right context
    02600  * structure, leave context list locked and call ast_context_remove_include2
    02601  * which removes include, unlock contexts list and return ...
    02602  */
    02603 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
    02604 {
    02605    struct ast_context *c;
    02606
    02607    if (ast_lock_contexts()) return -1;
    02608
    02609    /* walk contexts and search for the right one ...*/
    02610    c = ast_walk_contexts(NULL);
    02611    while (c) {
    02612       /* we found one ... */
    02613       if (!strcmp(ast_get_context_name(c), context)) {
    02614          int ret;
    02615          /* remove include from this context ... */
    02616          ret = ast_context_remove_include2(c, include, registrar);
    02617
    02618          ast_unlock_contexts();
    02619
    02620          /* ... return results */
    02621          return ret;
    02622       }
    02623       c = ast_walk_contexts(c);
    02624    }
    02625
    02626    /* we can't find the right one context */
    02627    ast_unlock_contexts();
    02628    return -1;
    02629 }
    02630
    02631 /*
    02632  * When we call this function, &conlock lock must be locked, because when
    02633  * we giving *con argument, some process can remove/change this context
    02634  * and after that there can be segfault.
    02635  *
    02636  * This function locks given context, removes include, unlock context and
    02637  * return.
    02638  */
    02639 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
    02640 {
    02641    struct ast_include *i, *pi = NULL;
    02642
    02643    if (ast_mutex_lock(&con->lock)) return -1;
    02644
    02645    /* walk includes */
    02646    i = con->includes;
    02647    while (i) {
    02648       /* find our include */
    02649       if (!strcmp(i->name, include) &&
    02650          (!registrar || !strcmp(i->registrar, registrar))) {
    02651          /* remove from list */
    02652          if (pi)
    02653             pi->next = i->next;
    02654          else
    02655             con->includes = i->next;
    02656          /* free include and return */
    02657          free(i);
    02658          ast_mutex_unlock(&con->lock);
    02659          return 0;
    02660       }
    02661       pi = i;
    02662       i = i->next;
    02663    }
    02664
    02665    /* we can't find the right include */
    02666    ast_mutex_unlock(&con->lock);
    02667    return -1;
    02668 }
    02669
    02670 /*!
    02671  * \note This function locks contexts list by &conlist, search for the rigt context
    02672  * structure, leave context list locked and call ast_context_remove_switch2
    02673  * which removes switch, unlock contexts list and return ...
    02674  */
    02675 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
    02676 {
    02677    struct ast_context *c;
    02678
    02679    if (ast_lock_contexts()) return -1;
    02680
    02681    /* walk contexts and search for the right one ...*/
    02682    c = ast_walk_contexts(NULL);
    02683    while (c) {
    02684       /* we found one ... */
    02685       if (!strcmp(ast_get_context_name(c), context)) {
    02686          int ret;
    02687          /* remove switch from this context ... */
    02688          ret = ast_context_remove_switch2(c, sw, data, registrar);
    02689
    02690          ast_unlock_contexts();
    02691
    02692          /* ... return results */
    02693          return ret;
    02694       }
    02695       c = ast_walk_contexts(c);
    02696    }
    02697
    02698    /* we can't find the right one context */
    02699    ast_unlock_contexts();
    02700    return -1;
    02701 }
    02702
    02703 /*!
    02704  * \brief This function locks given context, removes switch, unlock context and
    02705  * return.
    02706  * \note When we call this function, &conlock lock must be locked, because when
    02707  * we giving *con argument, some process can remove/change this context
    02708  * and after that there can be segfault.
    02709  *
    02710  */
    02711 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
    02712 {
    02713    struct ast_sw *i, *pi = NULL;
    02714
    02715    if (ast_mutex_lock(&con->lock)) return -1;
    02716
    02717    /* walk switchs */
    02718    i = con->alts;
    02719    while (i) {
    02720       /* find our switch */
    02721       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
    02722          (!registrar || !strcmp(i->registrar, registrar))) {
    02723          /* remove from list */
    02724          if (pi)
    02725             pi->next = i->next;
    02726          else
    02727             con->alts = i->next;
    02728          /* free switch and return */
    02729          free(i);
    02730          ast_mutex_unlock(&con->lock);
    02731          return 0;
    02732       }
    02733       pi = i;
    02734       i = i->next;
    02735    }
    02736
    02737    /* we can't find the right switch */
    02738    ast_mutex_unlock(&con->lock);
    02739    return -1;
    02740 }
    02741
    02742 /*
    02743  * \note This functions lock contexts list, search for the right context,
    02744  * call ast_context_remove_extension2, unlock contexts list and return.
    02745  * In this function we are using
    02746  */
    02747 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
    02748 {
    02749    struct ast_context *c;
    02750
    02751    if (ast_lock_contexts()) return -1;
    02752
    02753    /* walk contexts ... */
    02754    c = ast_walk_contexts(NULL);
    02755    while (c) {
    02756       /* ... search for the right one ... */
    02757       if (!strcmp(ast_get_context_name(c), context)) {
    02758          /* ... remove extension ... */
    02759          int ret = ast_context_remove_extension2(c, extension, priority,
    02760             registrar);
    02761          /* ... unlock contexts list and return */
    02762          ast_unlock_contexts();
    02763          return ret;
    02764       }
    02765       c = ast_walk_contexts(c);
    02766    }
    02767
    02768    /* we can't find the right context */
    02769    ast_unlock_contexts();
    02770    return -1;
    02771 }
    02772
    02773 /*!
    02774  * \brief This functionc locks given context, search for the right extension and
    02775  * fires out all peer in this extensions with given priority. If priority
    02776  * is set to 0, all peers are removed. After that, unlock context and
    02777  * return.
    02778  * \note When do you want to call this function, make sure that &conlock is locked,
    02779  * because some process can handle with your *con context before you lock
    02780  * it.
    02781  *
    02782  */
    02783 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
    02784 {
    02785    struct ast_exten *exten, *prev_exten = NULL;
    02786
    02787    if (ast_mutex_lock(&con->lock)) return -1;
    02788
    02789    /* go through all extensions in context and search the right one ... */
    02790    exten = con->root;
    02791    while (exten) {
    02792
    02793       /* look for right extension */
    02794       if (!strcmp(exten->exten, extension) &&
    02795          (!registrar || !strcmp(exten->registrar, registrar))) {
    02796          struct ast_exten *peer;
    02797
    02798          /* should we free all peers in this extension? (priority == 0)? */
    02799          if (priority == 0) {
    02800             /* remove this extension from context list */
    02801             if (prev_exten)
    02802                prev_exten->next = exten->next;
    02803             else
    02804                con->root = exten->next;
    02805
    02806             /* fire out all peers */
    02807             peer = exten;
    02808             while (peer) {
    02809                exten = peer->peer;
    02810
    02811                if (!peer->priority==PRIORITY_HINT)
    02812                    ast_remove_hint(peer);
    02813
    02814                peer->datad(peer->data);
    02815                free(peer);
    02816
    02817                peer = exten;
    02818             }
    02819
    02820             ast_mutex_unlock(&con->lock);
    02821             return 0;
    02822          } else {
    02823             /* remove only extension with exten->priority == priority */
    02824             struct ast_exten *previous_peer = NULL;
    02825
    02826             peer = exten;
    02827             while (peer) {
    02828                /* is this our extension? */
    02829                if (peer->priority == priority &&
    02830                   (!registrar || !strcmp(peer->registrar, registrar) )) {
    02831                   /* we are first priority extension? */
    02832                   if (!previous_peer) {
    02833                      /* exists previous extension here? */
    02834                      if (prev_exten) {
    02835                         /* yes, so we must change next pointer in
    02836                          * previous connection to next peer
    02837                          */
    02838                         if (peer->peer) {
    02839                            prev_exten->next = peer->peer;
    02840                            peer->peer->next = exten->next;
    02841                         } else
    02842                            prev_exten->next = exten->next;
    02843                      } else {
    02844                         /* no previous extension, we are first
    02845                          * extension, so change con->root ...
    02846                          */
    02847                         if (peer->peer)
    02848                            con->root = peer->peer;
    02849                         else
    02850                            con->root = exten->next;
    02851                      }
    02852                   } else {
    02853                      /* we are not first priority in extension */
    02854                      previous_peer->peer = peer->peer;
    02855                   }
    02856
    02857                   /* now, free whole priority extension */
    02858                   if (peer->priority==PRIORITY_HINT)
    02859                       ast_remove_hint(peer);
    02860                   peer->datad(peer->data);
    02861                   free(peer);
    02862
    02863                   ast_mutex_unlock(&con->lock);
    02864                   return 0;
    02865                } else {
    02866                   /* this is not right extension, skip to next peer */
    02867                   previous_peer = peer;
    02868                   peer = peer->peer;
    02869                }
    02870             }
    02871
    02872             ast_mutex_unlock(&con->lock);
    02873             return -1;
    02874          }
    02875       }
    02876
    02877       prev_exten = exten;
    02878       exten = exten->next;
    02879    }
    02880
    02881    /* we can't find right extension */
    02882    ast_mutex_unlock(&con->lock);
    02883    return -1;
    02884 }
    02885
    02886
    02887 /*! \brief Dynamically register a new dial plan application */
    02888 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
    02889 {
    02890    struct ast_app *tmp, *prev, *cur;
    02891    char tmps[80];
    02892    int length;
    02893    length = sizeof(struct ast_app);
    02894    length += strlen(app) + 1;
    02895    if (ast_mutex_lock(&applock)) {
    02896       ast_log(LOG_ERROR, "Unable to lock application list\n");
    02897       return -1;
    02898    }
    02899    tmp = apps;
    02900    while(tmp) {
    02901       if (!strcasecmp(app, tmp->name)) {
    02902          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
    02903          ast_mutex_unlock(&applock);
    02904          return -1;
    02905       }
    02906       tmp = tmp->next;
    02907    }
    02908    tmp = malloc(length);
    02909    if (tmp) {
    02910       memset(tmp, 0, length);
    02911       strcpy(tmp->name, app);
    02912       tmp->execute = execute;
    02913       tmp->synopsis = synopsis;
    02914       tmp->description = description;
    02915       /* Store in alphabetical order */
    02916       cur = apps;
    02917       prev = NULL;
    02918       while(cur) {
    02919          if (strcasecmp(tmp->name, cur->name) < 0)
    02920             break;
    02921          prev = cur;
    02922          cur = cur->next;
    02923       }
    02924       if (prev) {
    02925          tmp->next = prev->next;
    02926          prev->next = tmp;
    02927       } else {
    02928          tmp->next = apps;
    02929          apps = tmp;
    02930       }
    02931    } else {
    02932       ast_log(LOG_ERROR, "Out of memory\n");
    02933       ast_mutex_unlock(&applock);
    02934       return -1;
    02935    }
    02936    if (option_verbose > 1)
    02937       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
    02938    ast_mutex_unlock(&applock);
    02939    return 0;
    02940 }
    02941
    02942 int ast_register_switch(struct ast_switch *sw)
    02943 {
    02944    struct ast_switch *tmp, *prev=NULL;
    02945    if (ast_mutex_lock(&switchlock)) {
    02946       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
    02947       return -1;
    02948    }
    02949    tmp = switches;
    02950    while(tmp) {
    02951       if (!strcasecmp(tmp->name, sw->name))
    02952          break;
    02953       prev = tmp;
    02954       tmp = tmp->next;
    02955    }
    02956    if (tmp) {
    02957       ast_mutex_unlock(&switchlock);
    02958       ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
    02959       return -1;
    02960    }
    02961    sw->next = NULL;
    02962    if (prev)
    02963       prev->next = sw;
    02964    else
    02965       switches = sw;
    02966    ast_mutex_unlock(&switchlock);
    02967    return 0;
    02968 }
    02969
    02970 void ast_unregister_switch(struct ast_switch *sw)
    02971 {
    02972    struct ast_switch *tmp, *prev=NULL;
    02973    if (ast_mutex_lock(&switchlock)) {
    02974       ast_log(LOG_ERROR, "Unable to lock switch lock\n");
    02975       return;
    02976    }
    02977    tmp = switches;
    02978    while(tmp) {
    02979       if (tmp == sw) {
    02980          if (prev)
    02981             prev->next = tmp->next;
    02982          else
    02983             switches = tmp->next;
    02984          tmp->next = NULL;
    02985          break;
    02986       }
    02987       prev = tmp;
    02988       tmp = tmp->next;
    02989    }
    02990    ast_mutex_unlock(&switchlock);
    02991 }
    02992
    02993 /*
    02994  * Help for CLI commands ...
    02995  */
    02996 static char show_application_help[] =
    02997 "Usage: show application <application> [<application> [<application> [...]]]\n"
    02998 "       Describes a particular application.\n";
    02999
    03000 static char show_functions_help[] =
    03001 "Usage: show functions\n"
    03002 "       List builtin functions accessable as $(function args)\n";
    03003
    03004 static char show_function_help[] =
    03005 "Usage: show function <function>\n"
    03006 "       Describe a particular dialplan function.\n";
    03007
    03008 static char show_applications_help[] =
    03009 "Usage: show applications [{like|describing} <text>]\n"
    03010 "       List applications which are currently available.\n"
    03011 "       If 'like', <text> will be a substring of the app name\n"
    03012 "       If 'describing', <text> will be a substring of the description\n";
    03013
    03014 static char show_dialplan_help[] =
    03015 "Usage: show dialplan [exten@][context]\n"
    03016 "       Show dialplan\n";
    03017
    03018 static char show_switches_help[] =
    03019 "Usage: show switches\n"
    03020 "       Show registered switches\n";
    03021
    03022 static char show_hints_help[] =
    03023 "Usage: show hints\n"
    03024 "       Show registered hints\n";
    03025
    03026
    03027 /*
    03028  * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
    03029  *
    03030  */
    03031
    03032 /*
    03033  * \brief 'show application' CLI command implementation functions ...
    03034  */
    03035
    03036 /*
    03037  * There is a possibility to show informations about more than one
    03038  * application at one time. You can type 'show application Dial Echo' and
    03039  * you will see informations about these two applications ...
    03040  */
    03041 static char *complete_show_application(char *line, char *word,
    03042    int pos, int state)
    03043 {
    03044    struct ast_app *a;
    03045    int which = 0;
    03046
    03047    /* try to lock applications list ... */
    03048    if (ast_mutex_lock(&applock)) {
    03049       ast_log(LOG_ERROR, "Unable to lock application list\n");
    03050       return NULL;
    03051    }
    03052
    03053    /* ... walk all applications ... */
    03054    a = apps;
    03055    while (a) {
    03056       /* ... check if word matches this application ... */
    03057       if (!strncasecmp(word, a->name, strlen(word))) {
    03058          /* ... if this is right app serve it ... */
    03059          if (++which > state) {
    03060             char *ret = strdup(a->name);
    03061             ast_mutex_unlock(&applock);
    03062             return ret;
    03063          }
    03064       }
    03065       a = a->next;
    03066    }
    03067
    03068    /* no application match */
    03069    ast_mutex_unlock(&applock);
    03070    return NULL;
    03071 }
    03072
    03073 static int handle_show_application(int fd, int argc, char *argv[])
    03074 {
    03075    struct ast_app *a;
    03076    int app, no_registered_app = 1;
    03077
    03078    if (argc < 3) return RESULT_SHOWUSAGE;
    03079
    03080    /* try to lock applications list ... */
    03081    if (ast_mutex_lock(&applock)) {
    03082       ast_log(LOG_ERROR, "Unable to lock application list\n");
    03083       return -1;
    03084    }
    03085
    03086    /* ... go through all applications ... */
    03087    a = apps;
    03088    while (a) {
    03089       /* ... compare this application name with all arguments given
    03090        * to 'show application' command ... */
    03091       for (app = 2; app < argc; app++) {
    03092          if (!strcasecmp(a->name, argv[app])) {
    03093             /* Maximum number of characters added by terminal coloring is 22 */
    03094             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
    03095             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
    03096             int synopsis_size, description_size;
    03097
    03098             no_registered_app = 0;
    03099
    03100             if (a->synopsis)
    03101                synopsis_size = strlen(a->synopsis) + 23;
    03102             else
    03103                synopsis_size = strlen("Not available") + 23;
    03104             synopsis = alloca(synopsis_size);
    03105
    03106             if (a->description)
    03107                description_size = strlen(a->description) + 23;
    03108             else
    03109                description_size = strlen("Not available") + 23;
    03110             description = alloca(description_size);
    03111
    03112             if (synopsis && description) {
    03113                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
    03114                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
    03115                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
    03116                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
    03117                term_color(synopsis,
    03118                            a->synopsis ? a->synopsis : "Not available",
    03119                            COLOR_CYAN, 0, synopsis_size);
    03120                term_color(description,
    03121                            a->description ? a->description : "Not available",
    03122                            COLOR_CYAN, 0, description_size);
    03123
    03124                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
    03125             } else {
    03126                /* ... one of our applications, show info ...*/
    03127                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
    03128                   "[Synopsis]\n  %s\n\n"
    03129                   "[Description]\n%s\n",
    03130                   a->name,
    03131                   a->synopsis ? a->synopsis : "Not available",
    03132                   a->description ? a->description : "Not available");
    03133             }
    03134          }
    03135       }
    03136       a = a->next;
    03137    }
    03138
    03139    ast_mutex_unlock(&applock);
    03140
    03141    /* we found at least one app? no? */
    03142    if (no_registered_app) {
    03143       ast_cli(fd, "Your application(s) is (are) not registered\n");
    03144       return RESULT_FAILURE;
    03145    }
    03146
    03147    return RESULT_SUCCESS;
    03148 }
    03149
    03150 /*! \brief  handle_show_hints: CLI support for listing registred dial plan hints */
    03151 static int handle_show_hints(int fd, int argc, char *argv[])
    03152 {
    03153    struct ast_hint *hint;
    03154    int num = 0;
    03155    int watchers;
    03156    struct ast_state_cb *watcher;
    03157
    03158    if (!hints) {
    03159       ast_cli(fd, "There are no registered dialplan hints\n");
    03160       return RESULT_SUCCESS;
    03161    }
    03162    /* ... we have hints ... */
    03163    ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
    03164    if (ast_mutex_lock(&hintlock)) {
    03165       ast_log(LOG_ERROR, "Unable to lock hints\n");
    03166       return -1;
    03167    }
    03168    hint = hints;
    03169    while (hint) {
    03170       watchers = 0;
    03171       for (watcher = hint->callbacks; watcher; watcher = watcher->next)
    03172          watchers++;
    03173       ast_cli(fd, "   %-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
    03174          ast_get_extension_name(hint->exten), ast_get_extension_app(hint->exten),
    03175          ast_extension_state2str(hint->laststate), watchers);
    03176       num++;
    03177       hint = hint->next;
    03178    }
    03179    ast_cli(fd, "----------------\n");
    03180    ast_cli(fd, "- %d hints registered\n", num);
    03181    ast_mutex_unlock(&hintlock);
    03182    return RESULT_SUCCESS;
    03183 }
    03184
    03185 /*! \brief  handle_show_switches: CLI support for listing registred dial plan switches */
    03186 static int handle_show_switches(int fd, int argc, char *argv[])
    03187 {
    03188    struct ast_switch *sw;
    03189    if (!switches) {
    03190       ast_cli(fd, "There are no registered alternative switches\n");
    03191       return RESULT_SUCCESS;
    03192    }
    03193    /* ... we have applications ... */
    03194    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
    03195    if (ast_mutex_lock(&switchlock)) {
    03196       ast_log(LOG_ERROR, "Unable to lock switches\n");
    03197       return -1;
    03198    }
    03199    sw = switches;
    03200    while (sw) {
    03201       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
    03202       sw = sw->next;
    03203    }
    03204    ast_mutex_unlock(&switchlock);
    03205    return RESULT_SUCCESS;
    03206 }
    03207
    03208 /*
    03209  * 'show applications' CLI command implementation functions ...
    03210  */
    03211 static int handle_show_applications(int fd, int argc, char *argv[])
    03212 {
    03213    struct ast_app *a;
    03214    int like=0, describing=0;
    03215    int total_match = 0;    /* Number of matches in like clause */
    03216    int total_apps = 0;  /* Number of apps registered */
    03217
    03218    /* try to lock applications list ... */
    03219    if (ast_mutex_lock(&applock)) {
    03220       ast_log(LOG_ERROR, "Unable to lock application list\n");
    03221       return -1;
    03222    }
    03223
    03224    /* ... have we got at least one application (first)? no? */
    03225    if (!apps) {
    03226       ast_cli(fd, "There are no registered applications\n");
    03227       ast_mutex_unlock(&applock);
    03228       return -1;
    03229    }
    03230
    03231    /* show applications like <keyword> */
    03232    if ((argc == 4) && (!strcmp(argv[2], "like"))) {
    03233       like = 1;
    03234    } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
    03235       describing = 1;
    03236    }
    03237
    03238    /* show applications describing <keyword1> [<keyword2>] [...] */
    03239    if ((!like) && (!describing)) {
    03240       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
    03241    } else {
    03242       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
    03243    }
    03244
    03245    /* ... go through all applications ... */
    03246    for (a = apps; a; a = a->next) {
    03247       /* ... show informations about applications ... */
    03248       int printapp=0;
    03249       total_apps++;
    03250       if (like) {
    03251          if (strcasestr(a->name, argv[3])) {
    03252             printapp = 1;
    03253             total_match++;
    03254          }
    03255       } else if (describing) {
    03256          if (a->description) {
    03257             /* Match all words on command line */
    03258             int i;
    03259             printapp = 1;
    03260             for (i=3; i<argc; i++) {
    03261                if (!strcasestr(a->description, argv[i])) {
    03262                   printapp = 0;
    03263                } else {
    03264                   total_match++;
    03265                }
    03266             }
    03267          }
    03268       } else {
    03269          printapp = 1;
    03270       }
    03271
    03272       if (printapp) {
    03273          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
    03274       }
    03275    }
    03276    if ((!like) && (!describing)) {
    03277       ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
    03278    } else {
    03279       ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
    03280    }
    03281
    03282    /* ... unlock and return */
    03283    ast_mutex_unlock(&applock);
    03284
    03285    return RESULT_SUCCESS;
    03286 }
    03287
    03288 static char *complete_show_applications(char *line, char *word, int pos, int state)
    03289 {
    03290    if (pos == 2) {
    03291       if (ast_strlen_zero(word)) {
    03292          switch (state) {
    03293          case 0:
    03294             return strdup("like");
    03295          case 1:
    03296             return strdup("describing");
    03297          default:
    03298             return NULL;
    03299          }
    03300       } else if (! strncasecmp(word, "like", strlen(word))) {
    03301          if (state == 0) {
    03302             return strdup("like");
    03303          } else {
    03304             return NULL;
    03305          }
    03306       } else if (! strncasecmp(word, "describing", strlen(word))) {
    03307          if (state == 0) {
    03308             return strdup("describing");
    03309          } else {
    03310             return NULL;
    03311          }
    03312       }
    03313    }
    03314    return NULL;
    03315 }
    03316
    03317 /*
    03318  * 'show dialplan' CLI command implementation functions ...
    03319  */
    03320 static char *complete_show_dialplan_context(char *line, char *word, int pos,
    03321    int state)
    03322 {
    03323    struct ast_context *c;
    03324    int which = 0;
    03325
    03326    /* we are do completion of [exten@]context on second position only */
    03327    if (pos != 2) return NULL;
    03328
    03329    /* try to lock contexts list ... */
    03330    if (ast_lock_contexts()) {
    03331       ast_log(LOG_ERROR, "Unable to lock context list\n");
    03332       return NULL;
    03333    }
    03334
    03335    /* ... walk through all contexts ... */
    03336    c = ast_walk_contexts(NULL);
    03337    while(c) {
    03338       /* ... word matches context name? yes? ... */
    03339       if (!strncasecmp(word, ast_get_context_name(c), strlen(word))) {
    03340          /* ... for serve? ... */
    03341          if (++which > state) {
    03342             /* ... yes, serve this context name ... */
    03343             char *ret = strdup(ast_get_context_name(c));
    03344             ast_unlock_contexts();
    03345             return ret;
    03346          }
    03347       }
    03348       c = ast_walk_contexts(c);
    03349    }
    03350
    03351    /* ... unlock and return */
    03352    ast_unlock_contexts();
    03353    return NULL;
    03354 }
    03355
    03356 struct dialplan_counters {
    03357    int total_context;
    03358    int total_exten;
    03359    int total_prio;
    03360    int context_existence;
    03361    int extension_existence;
    03362 };
    03363
    03364 static int show_dialplan_helper(int fd, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, char *includes[])
    03365 {
    03366    struct ast_context *c;
    03367    int res=0, old_total_exten = dpc->total_exten;
    03368
    03369    /* try to lock contexts */
    03370    if (ast_lock_contexts()) {
    03371       ast_log(LOG_WARNING, "Failed to lock contexts list\n");
    03372       return -1;
    03373    }
    03374
    03375    /* walk all contexts ... */
    03376    for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) {
    03377       /* show this context? */
    03378       if (!context ||
    03379          !strcmp(ast_get_context_name(c), context)) {
    03380          dpc->context_existence = 1;
    03381
    03382          /* try to lock context before walking in ... */
    03383          if (!ast_lock_context(c)) {
    03384             struct ast_exten *e;
    03385             struct ast_include *i;
    03386             struct ast_ignorepat *ip;
    03387             struct ast_sw *sw;
    03388             char buf[256], buf2[256];
    03389             int context_info_printed = 0;
    03390
    03391             /* are we looking for exten too? if yes, we print context
    03392              * if we our extension only
    03393              */
    03394             if (!exten) {
    03395                dpc->total_context++;
    03396                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
    03397                   ast_get_context_name(c), ast_get_context_registrar(c));
    03398                context_info_printed = 1;
    03399             }
    03400
    03401             /* walk extensions ... */
    03402             for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) {
    03403                struct ast_exten *p;
    03404                int prio;
    03405
    03406                /* looking for extension? is this our extension? */
    03407                if (exten &&
    03408                   !ast_extension_match(ast_get_extension_name(e), exten))
    03409                {
    03410                   /* we are looking for extension and it's not our
    03411                    * extension, so skip to next extension */
    03412                   continue;
    03413                }
    03414
    03415                dpc->extension_existence = 1;
    03416
    03417                /* may we print context info? */
    03418                if (!context_info_printed) {
    03419                   dpc->total_context++;
    03420                   if (rinclude) {
    03421                      /* TODO Print more info about rinclude */
    03422                      ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
    03423                         ast_get_context_name(c),
    03424                         ast_get_context_registrar(c));
    03425                   } else {
    03426                      ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
    03427                         ast_get_context_name(c),
    03428                         ast_get_context_registrar(c));
    03429                   }
    03430                   context_info_printed = 1;
    03431                }
    03432                dpc->total_prio++;
    03433
    03434                /* write extension name and first peer */
    03435                bzero(buf, sizeof(buf));
    03436                snprintf(buf, sizeof(buf), "'%s' =>",
    03437                   ast_get_extension_name(e));
    03438
    03439                prio = ast_get_extension_priority(e);
    03440                if (prio == PRIORITY_HINT) {
    03441                   snprintf(buf2, sizeof(buf2),
    03442                      "hint: %s",
    03443                      ast_get_extension_app(e));
    03444                } else {
    03445                   snprintf(buf2, sizeof(buf2),
    03446                      "%d. %s(%s)",
    03447                      prio,
    03448                      ast_get_extension_app(e),
    03449                      (char *)ast_get_extension_app_data(e));
    03450                }
    03451
    03452                ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
    03453                   ast_get_extension_registrar(e));
    03454
    03455                dpc->total_exten++;
    03456                /* walk next extension peers */
    03457                for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) {
    03458                   dpc->total_prio++;
    03459                   bzero((void *)buf2, sizeof(buf2));
    03460                   bzero((void *)buf, sizeof(buf));
    03461                   if (ast_get_extension_label(p))
    03462                      snprintf(buf, sizeof(buf), "   [%s]", ast_get_extension_label(p));
    03463                   prio = ast_get_extension_priority(p);
    03464                   if (prio == PRIORITY_HINT) {
    03465                      snprintf(buf2, sizeof(buf2),
    03466                         "hint: %s",
    03467                         ast_get_extension_app(p));
    03468                   } else {
    03469                      snprintf(buf2, sizeof(buf2),
    03470                         "%d. %s(%s)",
    03471                         prio,
    03472                         ast_get_extension_app(p),
    03473                         (char *)ast_get_extension_app_data(p));
    03474                   }
    03475
    03476                   ast_cli(fd,"  %-17s %-45s [%s]\n",
    03477                      buf, buf2,
    03478                      ast_get_extension_registrar(p));
    03479                }
    03480             }
    03481
    03482             /* walk included and write info ... */
    03483             for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) {
    03484                bzero(buf, sizeof(buf));
    03485                snprintf(buf, sizeof(buf), "'%s'",
    03486                   ast_get_include_name(i));
    03487                if (exten) {
    03488                   /* Check all includes for the requested extension */
    03489                   if (includecount >= AST_PBX_MAX_STACK) {
    03490                      ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
    03491                   } else {
    03492                      int dupe=0;
    03493                      int x;
    03494                      for (x=0;x<includecount;x++) {
    03495                         if (!strcasecmp(includes[x], ast_get_include_name(i))) {
    03496                            dupe++;
    03497                            break;
    03498                         }
    03499                      }
    03500                      if (!dupe) {
    03501                         includes[includecount] = (char *)ast_get_include_name(i);
    03502                         show_dialplan_helper(fd, (char *)ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
    03503                      } else {
    03504                         ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
    03505                      }
    03506                   }
    03507                } else {
    03508                   ast_cli(fd, "  Include =>        %-45s [%s]\n",
    03509                      buf, ast_get_include_registrar(i));
    03510                }
    03511             }
    03512
    03513             /* walk ignore patterns and write info ... */
    03514             for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) {
    03515                const char *ipname = ast_get_ignorepat_name(ip);
    03516                char ignorepat[AST_MAX_EXTENSION];
    03517                snprintf(buf, sizeof(buf), "'%s'", ipname);
    03518                snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
    03519                if ((!exten) || ast_extension_match(ignorepat, exten)) {
    03520                   ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
    03521                      buf, ast_get_ignorepat_registrar(ip));
    03522                }
    03523             }
    03524             if (!rinclude) {
    03525                for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) {
    03526                   snprintf(buf, sizeof(buf), "'%s/%s'",
    03527                      ast_get_switch_name(sw),
    03528                      ast_get_switch_data(sw));
    03529                   ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
    03530                      buf, ast_get_switch_registrar(sw));
    03531                }
    03532             }
    03533
    03534             ast_unlock_context(c);
    03535
    03536             /* if we print something in context, make an empty line */
    03537             if (context_info_printed) ast_cli(fd, "\r\n");
    03538          }
    03539       }
    03540    }
    03541    ast_unlock_contexts();
    03542
    03543    if (dpc->total_exten == old_total_exten) {
    03544       /* Nothing new under the sun */
    03545       return -1;
    03546    } else {
    03547       return res;
    03548    }
    03549 }
    03550
    03551 static int handle_show_dialplan(int fd, int argc, char *argv[])
    03552 {
    03553    char *exten = NULL, *context = NULL;
    03554    /* Variables used for different counters */
    03555    struct dialplan_counters counters;
    03556    char *incstack[AST_PBX_MAX_STACK];
    03557    memset(&counters, 0, sizeof(counters));
    03558
    03559    if (argc != 2 && argc != 3)
    03560       return RESULT_SHOWUSAGE;
    03561
    03562    /* we obtain [exten@]context? if yes, split them ... */
    03563    if (argc == 3) {
    03564       char *splitter = ast_strdupa(argv[2]);
    03565       /* is there a '@' character? */
    03566       if (splitter && strchr(argv[2], '@')) {
    03567          /* yes, split into exten & context ... */
    03568          exten   = strsep(&splitter, "@");
    03569          context = splitter;
    03570
    03571          /* check for length and change to NULL if ast_strlen_zero() */
    03572          if (ast_strlen_zero(exten))
    03573             exten = NULL;
    03574          if (ast_strlen_zero(context))
    03575             context = NULL;
    03576          show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
    03577       } else {
    03578          /* no '@' char, only context given */
    03579          context = argv[2];
    03580          if (ast_strlen_zero(context))
    03581             context = NULL;
    03582          show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
    03583       }
    03584    } else {
    03585       /* Show complete dial plan */
    03586       show_dialplan_helper(fd, NULL, NULL, &counters, NULL, 0, incstack);
    03587    }
    03588
    03589    /* check for input failure and throw some error messages */
    03590    if (context && !counters.context_existence) {
    03591       ast_cli(fd, "There is no existence of '%s' context\n", context);
    03592       return RESULT_FAILURE;
    03593    }
    03594
    03595    if (exten && !counters.extension_existence) {
    03596       if (context)
    03597          ast_cli(fd, "There is no existence of %s@%s extension\n",
    03598             exten, context);
    03599       else
    03600          ast_cli(fd,
    03601             "There is no existence of '%s' extension in all contexts\n",
    03602             exten);
    03603       return RESULT_FAILURE;
    03604    }
    03605
    03606    ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
    03607             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
    03608             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
    03609             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
    03610
    03611    /* everything ok */
    03612    return RESULT_SUCCESS;
    03613 }
    03614
    03615 /*
    03616  * CLI entries for upper commands ...
    03617  */
    03618 static struct ast_cli_entry pbx_cli[] = {
    03619    { { "show", "applications", NULL }, handle_show_applications,
    03620      "Shows registered dialplan applications", show_applications_help, complete_show_applications },
    03621    { { "show", "functions", NULL }, handle_show_functions,
    03622      "Shows registered dialplan functions", show_functions_help },
    03623    { { "show" , "function", NULL }, handle_show_function,
    03624      "Describe a specific dialplan function", show_function_help, complete_show_function },
    03625    { { "show", "application", NULL }, handle_show_application,
    03626      "Describe a specific dialplan application", show_application_help, complete_show_application },
    03627    { { "show", "dialplan", NULL }, handle_show_dialplan,
    03628      "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
    03629    { { "show", "switches", NULL },  handle_show_switches,
    03630      "Show alternative switches", show_switches_help },
    03631    { { "show", "hints", NULL }, handle_show_hints,
    03632      "Show dialplan hints", show_hints_help },
    03633 };
    03634
    03635 int ast_unregister_application(const char *app)
    03636 {
    03637    struct ast_app *tmp, *tmpl = NULL;
    03638    if (ast_mutex_lock(&applock)) {
    03639       ast_log(LOG_ERROR, "Unable to lock application list\n");
    03640       return -1;
    03641    }
    03642    tmp = apps;
    03643    while(tmp) {
    03644       if (!strcasecmp(app, tmp->name)) {
    03645          if (tmpl)
    03646             tmpl->next = tmp->next;
    03647          else
    03648             apps = tmp->next;
    03649          if (option_verbose > 1)
    03650             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
    03651          free(tmp);
    03652          ast_mutex_unlock(&applock);
    03653          return 0;
    03654       }
    03655       tmpl = tmp;
    03656       tmp = tmp->next;
    03657    }
    03658    ast_mutex_unlock(&applock);
    03659    return -1;
    03660 }
    03661
    03662 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
    03663 {
    03664    struct ast_context *tmp, **local_contexts;
    03665    int length;
    03666    length = sizeof(struct ast_context);
    03667    length += strlen(name) + 1;
    03668    if (!extcontexts) {
    03669       local_contexts = &contexts;
    03670       ast_mutex_lock(&conlock);
    03671    } else
    03672       local_contexts = extcontexts;
    03673
    03674    tmp = *local_contexts;
    03675    while(tmp) {
    03676       if (!strcasecmp(tmp->name, name)) {
    03677          ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
    03678          if (!extcontexts)
    03679             ast_mutex_unlock(&conlock);
    03680          return NULL;
    03681       }
    03682       tmp = tmp->next;
    03683    }
    03684    tmp = malloc(length);
    03685    if (tmp) {
    03686       memset(tmp, 0, length);
    03687       ast_mutex_init(&tmp->lock);
    03688       strcpy(tmp->name, name);
    03689       tmp->root = NULL;
    03690       tmp->registrar = registrar;
    03691       tmp->next = *local_contexts;
    03692       tmp->includes = NULL;
    03693       tmp->ignorepats = NULL;
    03694       *local_contexts = tmp;
    03695       if (option_debug)
    03696          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
    03697       if (option_verbose > 2)
    03698          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
    03699    } else
    03700       ast_log(LOG_ERROR, "Out of memory\n");
    03701
    03702    if (!extcontexts)
    03703       ast_mutex_unlock(&conlock);
    03704    return tmp;
    03705 }
    03706
    03707 void __ast_context_destroy(struct ast_context *con, const char *registrar);
    03708
    03709 struct store_hint {
    03710    char *context;
    03711    char *exten;
    03712    struct ast_state_cb *callbacks;
    03713    int laststate;
    03714    AST_LIST_ENTRY(store_hint) list;
    03715    char data[1];
    03716 };
    03717
    03718 AST_LIST_HEAD(store_hints, store_hint);
    03719
    03720 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
    03721 {
    03722    struct ast_context *tmp, *lasttmp = NULL;
    03723    struct store_hints store;
    03724    struct store_hint *this;
    03725    struct ast_hint *hint;
    03726    struct ast_exten *exten;
    03727    int length;
    03728    struct ast_state_cb *thiscb, *prevcb;
    03729
    03730    memset(&store, 0, sizeof(store));
    03731    AST_LIST_HEAD_INIT(&store);
    03732
    03733    /* it is very important that this function hold the hintlock _and_ the conlock
    03734       during its operation; not only do we need to ensure that the list of contexts
    03735       and extensions does not change, but also that no hint callbacks (watchers) are
    03736       added or removed during the merge/delete process
    03737
    03738       in addition, the locks _must_ be taken in this order, because there are already
    03739       other code paths that use this order
    03740    */
    03741    ast_mutex_lock(&conlock);
    03742    ast_mutex_lock(&hintlock);
    03743
    03744    /* preserve all watchers for hints associated with this registrar */
    03745    for (hint = hints; hint; hint = hint->next) {
    03746       if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
    03747          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
    03748          this = calloc(1, length);
    03749          if (!this) {
    03750             ast_log(LOG_WARNING, "Could not allocate memory to preserve hint\n");
    03751             continue;
    03752          }
    03753          this->callbacks = hint->callbacks;
    03754          hint->callbacks = NULL;
    03755          this->laststate = hint->laststate;
    03756          this->context = this->data;
    03757          strcpy(this->data, hint->exten->parent->name);
    03758          this->exten = this->data + strlen(this->context) + 1;
    03759          strcpy(this->exten, hint->exten->exten);
    03760          AST_LIST_INSERT_HEAD(&store, this, list);
    03761       }
    03762    }
    03763
    03764    tmp = *extcontexts;
    03765    if (registrar) {
    03766       __ast_context_destroy(NULL,registrar);
    03767       while (tmp) {
    03768          lasttmp = tmp;
    03769          tmp = tmp->next;
    03770       }
    03771    } else {
    03772       while (tmp) {
    03773          __ast_context_destroy(tmp,tmp->registrar);
    03774          lasttmp = tmp;
    03775          tmp = tmp->next;
    03776       }
    03777    }
    03778    if (lasttmp) {
    03779       lasttmp->next = contexts;
    03780       contexts = *extcontexts;
    03781       *extcontexts = NULL;
    03782    } else
    03783       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
    03784
    03785    /* restore the watchers for hints that can be found; notify those that
    03786       cannot be restored
    03787    */
    03788    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
    03789       exten = ast_hint_extension(NULL, this->context, this->exten);
    03790       /* Find the hint in the list of hints */
    03791       for (hint = hints; hint; hint = hint->next) {
    03792          if (hint->exten == exten)
    03793             break;
    03794       }
    03795       if (!exten || !hint) {
    03796          /* this hint has been removed, notify the watchers */
    03797          prevcb = NULL;
    03798          thiscb = this->callbacks;
    03799          while (thiscb) {
    03800             prevcb = thiscb;
    03801             thiscb = thiscb->next;
    03802             prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
    03803             free(prevcb);
    03804             }
    03805       } else {
    03806          thiscb = this->callbacks;
    03807          while (thiscb->next)
    03808             thiscb = thiscb->next;
    03809          thiscb->next = hint->callbacks;
    03810          hint->callbacks = this->callbacks;
    03811          hint->laststate = this->laststate;
    03812       }
    03813       free(this);
    03814    }
    03815
    03816    ast_mutex_unlock(&hintlock);
    03817    ast_mutex_unlock(&conlock);
    03818
    03819    return;
    03820 }
    03821
    03822 /*
    03823  * errno values
    03824  *  EBUSY  - can't lock
    03825  *  ENOENT - no existence of context
    03826  */
    03827 int ast_context_add_include(const char *context, const char *include, const char *registrar)
    03828 {
    03829    struct ast_context *c;
    03830
    03831    if (ast_lock_contexts()) {
    03832       errno = EBUSY;
    03833       return -1;
    03834    }
    03835
    03836    /* walk contexts ... */
    03837    c = ast_walk_contexts(NULL);
    03838    while (c) {
    03839       /* ... search for the right one ... */
    03840       if (!strcmp(ast_get_context_name(c), context)) {
    03841          int ret = ast_context_add_include2(c, include, registrar);
    03842          /* ... unlock contexts list and return */
    03843          ast_unlock_contexts();
    03844          return ret;
    03845       }
    03846       c = ast_walk_contexts(c);
    03847    }
    03848
    03849    /* we can't find the right context */
    03850    ast_unlock_contexts();
    03851    errno = ENOENT;
    03852    return -1;
    03853 }
    03854
    03855 #define FIND_NEXT \
    03856 do { \
    03857    c = info; \
    03858    while(*c && (*c != '|')) c++; \
    03859    if (*c) { *c = '\0'; c++; } else c = NULL; \
    03860 } while(0)
    03861
    03862 static void get_timerange(struct ast_timing *i, char *times)
    03863 {
    03864    char *e;
    03865    int x;
    03866    int s1, s2;
    03867    int e1, e2;
    03868    /* int cth, ctm; */
    03869
    03870    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
    03871    memset(i->minmask, 0, sizeof(i->minmask));
    03872
    03873    /* Star is all times */
    03874    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
    03875       for (x=0; x<24; x++)
    03876          i->minmask[x] = (1 << 30) - 1;
    03877       return;
    03878    }
    03879    /* Otherwise expect a range */
    03880    e = strchr(times, '-');
    03881    if (!e) {
    03882       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
    03883       return;
    03884    }
    03885    *e = '\0';
    03886    e++;
    03887    while(*e && !isdigit(*e))
    03888       e++;
    03889    if (!*e) {
    03890       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
    03891       return;
    03892    }
    03893    if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
    03894       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
    03895       return;
    03896    }
    03897    if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
    03898       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
    03899       return;
    03900    }
    03901
    03902 #if 1
    03903    s1 = s1 * 30 + s2/2;
    03904    if ((s1 < 0) || (s1 >= 24*30)) {
    03905       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
    03906       return;
    03907    }
    03908    e1 = e1 * 30 + e2/2;
    03909    if ((e1 < 0) || (e1 >= 24*30)) {
    03910       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
    03911       return;
    03912    }
    03913    /* Go through the time and enable each appropriate bit */
    03914    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
    03915       i->minmask[x/30] |= (1 << (x % 30));
    03916    }
    03917    /* Do the last one */
    03918    i->minmask[x/30] |= (1 << (x % 30));
    03919 #else
    03920    for (cth=0; cth<24; cth++) {
    03921       /* Initialize masks to blank */
    03922       i->minmask[cth] = 0;
    03923       for (ctm=0; ctm<30; ctm++) {
    03924          if (
    03925          /* First hour with more than one hour */
    03926                (((cth == s1) && (ctm >= s2)) &&
    03927                 ((cth < e1)))
    03928          /* Only one hour */
    03929          ||    (((cth == s1) && (ctm >= s2)) &&
    03930                 ((cth == e1) && (ctm <= e2)))
    03931          /* In between first and last hours (more than 2 hours) */
    03932          ||    ((cth > s1) &&
    03933                 (cth < e1))
    03934          /* Last hour with more than one hour */
    03935          ||    ((cth > s1) &&
    03936                 ((cth == e1) && (ctm <= e2)))
    03937          )
    03938             i->minmask[cth] |= (1 << (ctm / 2));
    03939       }
    03940    }
    03941 #endif
    03942    /* All done */
    03943    return;
    03944 }
    03945
    03946 static char *days[] =
    03947 {
    03948    "sun",
    03949    "mon",
    03950    "tue",
    03951    "wed",
    03952    "thu",
    03953    "fri",
    03954    "sat",
    03955 };
    03956
    03957 /*! \brief  get_dow: Get day of week */
    03958 static unsigned int get_dow(char *dow)
    03959 {
    03960    char *c;
    03961    /* The following line is coincidence, really! */
    03962    int s, e, x;
    03963    unsigned int mask;
    03964
    03965    /* Check for all days */
    03966    if (ast_strlen_zero(dow) || !strcmp(dow, "*"))
    03967       return (1 << 7) - 1;
    03968    /* Get start and ending days */
    03969    c = strchr(dow, '-');
    03970    if (c) {
    03971       *c = '\0';
    03972       c++;
    03973    } else
    03974       c = NULL;
    03975    /* Find the start */
    03976    s = 0;
    03977    while((s < 7) && strcasecmp(dow, days[s])) s++;
    03978    if (s >= 7) {
    03979       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
    03980       return 0;
    03981    }
    03982    if (c) {
    03983       e = 0;
    03984       while((e < 7) && strcasecmp(c, days[e])) e++;
    03985       if (e >= 7) {
    03986          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
    03987          return 0;
    03988       }
    03989    } else
    03990       e = s;
    03991    mask = 0;
    03992    for (x=s; x != e; x = (x + 1) % 7) {
    03993       mask |= (1 << x);
    03994    }
    03995    /* One last one */
    03996    mask |= (1 << x);
    03997    return mask;
    03998 }
    03999
    04000 static unsigned int get_day(char *day)
    04001 {
    04002    char *c;
    04003    /* The following line is coincidence, really! */
    04004    int s, e, x;
    04005    unsigned int mask;
    04006
    04007    /* Check for all days */
    04008    if (ast_strlen_zero(day) || !strcmp(day, "*")) {
    04009       mask = (1 << 30)  + ((1 << 30) - 1);
    04010       return mask;
    04011    }
    04012    /* Get start and ending days */
    04013    c = strchr(day, '-');
    04014    if (c) {
    04015       *c = '\0';
    04016       c++;
    04017    }
    04018    /* Find the start */
    04019    if (sscanf(day, "%2d", &s) != 1) {
    04020       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
    04021       return 0;
    04022    }
    04023    if ((s < 1) || (s > 31)) {
    04024       ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
    04025       return 0;
    04026    }
    04027    s--;
    04028    if (c) {
    04029       if (sscanf(c, "%2d", &e) != 1) {
    04030          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
    04031          return 0;
    04032       }
    04033       if ((e < 1) || (e > 31)) {
    04034          ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
    04035          return 0;
    04036       }
    04037       e--;
    04038    } else
    04039       e = s;
    04040    mask = 0;
    04041    for (x=s; x!=e; x = (x + 1) % 31) {
    04042       mask |= (1 << x);
    04043    }
    04044    mask |= (1 << x);
    04045    return mask;
    04046 }
    04047
    04048 static char *months[] =
    04049 {
    04050    "jan",
    04051    "feb",
    04052    "mar",
    04053    "apr",
    04054    "may",
    04055    "jun",
    04056    "jul",
    04057    "aug",
    04058    "sep",
    04059    "oct",
    04060    "nov",
    04061    "dec",
    04062 };
    04063
    04064 static unsigned int get_month(char *mon)
    04065 {
    04066    char *c;
    04067    /* The following line is coincidence, really! */
    04068    int s, e, x;
    04069    unsigned int mask;
    04070
    04071    /* Check for all days */
    04072    if (ast_strlen_zero(mon) || !strcmp(mon, "*"))
    04073       return (1 << 12) - 1;
    04074    /* Get start and ending days */
    04075    c = strchr(mon, '-');
    04076    if (c) {
    04077       *c = '\0';
    04078       c++;
    04079    }
    04080    /* Find the start */
    04081    s = 0;
    04082    while((s < 12) && strcasecmp(mon, months[s])) s++;
    04083    if (s >= 12) {
    04084       ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
    04085       return 0;
    04086    }
    04087    if (c) {
    04088       e = 0;
    04089       while((e < 12) && strcasecmp(c, months[e])) e++;
    04090       if (e >= 12) {
    04091          ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
    04092          return 0;
    04093       }
    04094    } else
    04095       e = s;
    04096    mask = 0;
    04097    for (x=s; x!=e; x = (x + 1) % 12) {
    04098       mask |= (1 << x);
    04099    }
    04100    /* One last one */
    04101    mask |= (1 << x);
    04102    return mask;
    04103 }
    04104
    04105 int ast_build_timing(struct ast_timing *i, char *info_in)
    04106 {
    04107    char info_save[256];
    04108    char *info;
    04109    char *c;
    04110
    04111    /* Check for empty just in case */
    04112    if (ast_strlen_zero(info_in))
    04113       return 0;
    04114    /* make a copy just in case we were passed a static string */
    04115    ast_copy_string(info_save, info_in, sizeof(info_save));
    04116    info = info_save;
    04117    /* Assume everything except time */
    04118    i->monthmask = (1 << 12) - 1;
    04119    i->daymask = (1 << 30) - 1 + (1 << 30);
    04120    i->dowmask = (1 << 7) - 1;
    04121    /* Avoid using str tok */
    04122    FIND_NEXT;
    04123    /* Info has the time range, start with that */
    04124    get_timerange(i, info);
    04125    info = c;
    04126    if (!info)
    04127       return 1;
    04128    FIND_NEXT;
    04129    /* Now check for day of week */
    04130    i->dowmask = get_dow(info);
    04131
    04132    info = c;
    04133    if (!info)
    04134       return 1;
    04135    FIND_NEXT;
    04136    /* Now check for the day of the month */
    04137    i->daymask = get_day(info);
    04138    info = c;
    04139    if (!info)
    04140       return 1;
    04141    FIND_NEXT;
    04142    /* And finally go for the month */
    04143    i->monthmask = get_month(info);
    04144
    04145    return 1;
    04146 }
    04147
    04148 int ast_check_timing(struct ast_timing *i)
    04149 {
    04150    struct tm tm;
    04151    time_t t;
    04152
    04153    time(&t);
    04154    localtime_r(&t,&tm);
    04155
    04156    /* If it's not the right month, return */
    04157    if (!(i->monthmask & (1 << tm.tm_mon))) {
    04158       return 0;
    04159    }
    04160
    04161    /* If it's not that time of the month.... */
    04162    /* Warning, tm_mday has range 1..31! */
    04163    if (!(i->daymask & (1 << (tm.tm_mday-1))))
    04164       return 0;
    04165
    04166    /* If it's not the right day of the week */
    04167    if (!(i->dowmask & (1 << tm.tm_wday)))
    04168       return 0;
    04169
    04170    /* Sanity check the hour just to be safe */
    04171    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
    04172       ast_log(LOG_WARNING, "Insane time...\n");
    04173       return 0;
    04174    }
    04175
    04176    /* Now the tough part, we calculate if it fits
    04177       in the right time based on min/hour */
    04178    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
    04179       return 0;
    04180
    04181    /* If we got this far, then we're good */
    04182    return 1;
    04183 }
    04184
    04185 /*
    04186  * errno values
    04187  *  ENOMEM - out of memory
    04188  *  EBUSY  - can't lock
    04189  *  EEXIST - already included
    04190  *  EINVAL - there is no existence of context for inclusion
    04191  */
    04192 int ast_context_add_include2(struct ast_context *con, const char *value,
    04193    const char *registrar)
    04194 {
    04195    struct ast_include *new_include;
    04196    char *c;
    04197    struct ast_include *i, *il = NULL; /* include, include_last */
    04198    int length;
    04199    char *p;
    04200
    04201    length = sizeof(struct ast_include);
    04202    length += 2 * (strlen(value) + 1);
    04203
    04204    /* allocate new include structure ... */
    04205    if (!(new_include = malloc(length))) {
    04206       ast_log(LOG_ERROR, "Out of memory\n");
    04207       errno = ENOMEM;
    04208       return -1;
    04209    }
    04210
    04211    /* ... fill in this structure ... */
    04212    memset(new_include, 0, length);
    04213    p = new_include->stuff;
    04214    new_include->name = p;
    04215    strcpy(new_include->name, value);
    04216    p += strlen(value) + 1;
    04217    new_include->rname = p;
    04218    strcpy(new_include->rname, value);
    04219    c = new_include->rname;
    04220    /* Strip off timing info */
    04221    while(*c && (*c != '|'))
    04222       c++;
    04223    /* Process if it's there */
    04224    if (*c) {
    04225            new_include->hastime = ast_build_timing(&(new_include->timing), c+1);
    04226       *c = '\0';
    04227    }
    04228    new_include->next      = NULL;
    04229    new_include->registrar = registrar;
    04230
    04231    /* ... try to lock this context ... */
    04232    if (ast_mutex_lock(&con->lock)) {
    04233       free(new_include);
    04234       errno = EBUSY;
    04235       return -1;
    04236    }
    04237
    04238    /* ... go to last include and check if context is already included too... */
    04239    i = con->includes;
    04240    while (i) {
    04241       if (!strcasecmp(i->name, new_include->name)) {
    04242          free(new_include);
    04243          ast_mutex_unlock(&con->lock);
    04244          errno = EEXIST;
    04245          return -1;
    04246       }
    04247       il = i;
    04248       i = i->next;
    04249    }
    04250
    04251    /* ... include new context into context list, unlock, return */
    04252    if (il)
    04253       il->next = new_include;
    04254    else
    04255       con->includes = new_include;
    04256    if (option_verbose > 2)
    04257       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
    04258    ast_mutex_unlock(&con->lock);
    04259
    04260    return 0;
    04261 }
    04262
    04263 /*
    04264  * errno values
    04265  *  EBUSY  - can't lock
    04266  *  ENOENT - no existence of context
    04267  */
    04268 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
    04269 {
    04270    struct ast_context *c;
    04271
    04272    if (ast_lock_contexts()) {
    04273       errno = EBUSY;
    04274       return -1;
    04275    }
    04276
    04277    /* walk contexts ... */
    04278    c = ast_walk_contexts(NULL);
    04279    while (c) {
    04280       /* ... search for the right one ... */
    04281       if (!strcmp(ast_get_context_name(c), context)) {
    04282          int ret = ast_context_add_switch2(c, sw, data, eval, registrar);
    04283          /* ... unlock contexts list and return */
    04284          ast_unlock_contexts();
    04285          return ret;
    04286       }
    04287       c = ast_walk_contexts(c);
    04288    }
    04289
    04290    /* we can't find the right context */
    04291    ast_unlock_contexts();
    04292    errno = ENOENT;
    04293    return -1;
    04294 }
    04295
    04296 /*
    04297  * errno values
    04298  *  ENOMEM - out of memory
    04299  *  EBUSY  - can't lock
    04300  *  EEXIST - already included
    04301  *  EINVAL - there is no existence of context for inclusion
    04302  */
    04303 int ast_context_add_switch2(struct ast_context *con, const char *value,
    04304    const char *data, int eval, const char *registrar)
    04305 {
    04306    struct ast_sw *new_sw;
    04307    struct ast_sw *i, *il = NULL; /* sw, sw_last */
    04308    int length;
    04309    char *p;
    04310
    04311    length = sizeof(struct ast_sw);
    04312    length += strlen(value) + 1;
    04313    if (data)
    04314       length += strlen(data);
    04315    length++;
    04316    if (eval) {
    04317       /* Create buffer for evaluation of variables */
    04318       length += SWITCH_DATA_LENGTH;
    04319       length++;
    04320    }
    04321
    04322    /* allocate new sw structure ... */
    04323    if (!(new_sw = malloc(length))) {
    04324       ast_log(LOG_ERROR, "Out of memory\n");
    04325       errno = ENOMEM;
    04326       return -1;
    04327    }
    04328
    04329    /* ... fill in this structure ... */
    04330    memset(new_sw, 0, length);
    04331    p = new_sw->stuff;
    04332    new_sw->name = p;
    04333    strcpy(new_sw->name, value);
    04334    p += strlen(value) + 1;
    04335    new_sw->data = p;
    04336    if (data) {
    04337       strcpy(new_sw->data, data);
    04338       p += strlen(data) + 1;
    04339    } else {
    04340       strcpy(new_sw->data, "");
    04341       p++;
    04342    }
    04343    if (eval)
    04344       new_sw->tmpdata = p;
    04345    new_sw->next      = NULL;
    04346    new_sw->eval     = eval;
    04347    new_sw->registrar = registrar;
    04348
    04349    /* ... try to lock this context ... */
    04350    if (ast_mutex_lock(&con->lock)) {
    04351       free(new_sw);
    04352       errno = EBUSY;
    04353       return -1;
    04354    }
    04355
    04356    /* ... go to last sw and check if context is already swd too... */
    04357    i = con->alts;
    04358    while (i) {
    04359       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
    04360          free(new_sw);
    04361          ast_mutex_unlock(&con->lock);
    04362          errno = EEXIST;
    04363          return -1;
    04364       }
    04365       il = i;
    04366       i = i->next;
    04367    }
    04368
    04369    /* ... sw new context into context list, unlock, return */
    04370    if (il)
    04371       il->next = new_sw;
    04372    else
    04373       con->alts = new_sw;
    04374    if (option_verbose > 2)
    04375       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
    04376    ast_mutex_unlock(&con->lock);
    04377
    04378    return 0;
    04379 }
    04380
    04381 /*
    04382  * EBUSY  - can't lock
    04383  * ENOENT - there is not context existence
    04384  */
    04385 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
    04386 {
    04387    struct ast_context *c;
    04388
    04389    if (ast_lock_contexts()) {
    04390       errno = EBUSY;
    04391       return -1;
    04392    }
    04393
    04394    c = ast_walk_contexts(NULL);
    04395    while (c) {
    04396       if (!strcmp(ast_get_context_name(c), context)) {
    04397          int ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
    04398          ast_unlock_contexts();
    04399          return ret;
    04400       }
    04401       c = ast_walk_contexts(c);
    04402    }
    04403
    04404    ast_unlock_contexts();
    04405    errno = ENOENT;
    04406    return -1;
    04407 }
    04408
    04409 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
    04410 {
    04411    struct ast_ignorepat *ip, *ipl = NULL;
    04412
    04413    if (ast_mutex_lock(&con->lock)) {
    04414       errno = EBUSY;
    04415       return -1;
    04416    }
    04417
    04418    ip = con->ignorepats;
    04419    while (ip) {
    04420       if (!strcmp(ip->pattern, ignorepat) &&
    04421          (!registrar || (registrar == ip->registrar))) {
    04422          if (ipl) {
    04423             ipl->next = ip->next;
    04424             free(ip);
    04425          } else {
    04426             con->ignorepats = ip->next;
    04427             free(ip);
    04428          }
    04429          ast_mutex_unlock(&con->lock);
    04430          return 0;
    04431       }
    04432       ipl = ip; ip = ip->next;
    04433    }
    04434
    04435    ast_mutex_unlock(&con->lock);
    04436    errno = EINVAL;
    04437    return -1;
    04438 }
    04439
    04440 /*
    04441  * EBUSY - can't lock
    04442  * ENOENT - there is no existence of context
    04443  */
    04444 int ast_context_add_ignorepat(const char *con, const char *value, const char *registrar)
    04445 {
    04446    struct ast_context *c;
    04447
    04448    if (ast_lock_contexts()) {
    04449       errno = EBUSY;
    04450       return -1;
    04451    }
    04452
    04453    c = ast_walk_contexts(NULL);
    04454    while (c) {
    04455       if (!strcmp(ast_get_context_name(c), con)) {
    04456          int ret = ast_context_add_ignorepat2(c, value, registrar);
    04457          ast_unlock_contexts();
    04458          return ret;
    04459       }
    04460       c = ast_walk_contexts(c);
    04461    }
    04462
    04463    ast_unlock_contexts();
    04464    errno = ENOENT;
    04465    return -1;
    04466 }
    04467
    04468 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
    04469 {
    04470    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
    04471    int length;
    04472    length = sizeof(struct ast_ignorepat);
    04473    length += strlen(value) + 1;
    04474    ignorepat = malloc(length);
    04475    if (!ignorepat) {
    04476       ast_log(LOG_ERROR, "Out of memory\n");
    04477       errno = ENOMEM;
    04478       return -1;
    04479    }
    04480    memset(ignorepat, 0, length);
    04481    strcpy(ignorepat->pattern, value);
    04482    ignorepat->next = NULL;
    04483    ignorepat->registrar = registrar;
    04484    ast_mutex_lock(&con->lock);
    04485    ignorepatc = con->ignorepats;
    04486    while(ignorepatc) {
    04487       ignorepatl = ignorepatc;
    04488       if (!strcasecmp(ignorepatc->pattern, value)) {
    04489          /* Already there */
    04490          ast_mutex_unlock(&con->lock);
    04491          errno = EEXIST;
    04492          return -1;
    04493       }
    04494       ignorepatc = ignorepatc->next;
    04495    }
    04496    if (ignorepatl)
    04497       ignorepatl->next = ignorepat;
    04498    else
    04499       con->ignorepats = ignorepat;
    04500    ast_mutex_unlock(&con->lock);
    04501    return 0;
    04502
    04503 }
    04504
    04505 int ast_ignore_pattern(const char *context, const char *pattern)
    04506 {
    04507    struct ast_context *con;
    04508    struct ast_ignorepat *pat;
    04509
    04510    con = ast_context_find(context);
    04511    if (con) {
    04512       pat = con->ignorepats;
    04513       while (pat) {
    04514          if (ast_extension_match(pat->pattern, pattern))
    04515             return 1;
    04516          pat = pat->next;
    04517       }
    04518    }
    04519    return 0;
    04520 }
    04521
    04522 /*
    04523  * EBUSY   - can't lock
    04524  * ENOENT  - no existence of context
    04525  *
    04526  */
    04527 int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid,
    04528    const char *application, void *data, void (*datad)(void *), const char *registrar)
    04529 {
    04530    struct ast_context *c;
    04531
    04532    if (ast_lock_contexts()) {
    04533       errno = EBUSY;
    04534       return -1;
    04535    }
    04536
    04537    c = ast_walk_contexts(NULL);
    04538    while (c) {
    04539       if (!strcmp(context, ast_get_context_name(c))) {
    04540          int ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
    04541             application, data, datad, registrar);
    04542          ast_unlock_contexts();
    04543          return ret;
    04544       }
    04545       c = ast_walk_contexts(c);
    04546    }
    04547
    04548    ast_unlock_contexts();
    04549    errno = ENOENT;
    04550    return -1;
    04551 }
    04552
    04553 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
    04554 {
    04555    if (!chan)
    04556       return -1;
    04557
    04558    if (!ast_strlen_zero(context))
    04559       ast_copy_string(chan->context, context, sizeof(chan->context));
    04560    if (!ast_strlen_zero(exten))
    04561       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
    04562    if (priority > -1) {
    04563       chan->priority = priority;
    04564       /* see flag description in channel.h for explanation */
    04565       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
    04566          chan->priority--;
    04567    }
    04568
    04569    return 0;
    04570 }
    04571
    04572 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
    04573 {
    04574    int res = 0;
    04575
    04576    ast_mutex_lock(&chan->lock);
    04577
    04578    if (chan->pbx) {
    04579       /* This channel is currently in the PBX */
    04580       ast_explicit_goto(chan, context, exten, priority);
    04581       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
    04582    } else {
    04583       /* In order to do it when the channel doesn't really exist within
    04584          the PBX, we have to make a new channel, masquerade, and start the PBX
    04585          at the new location */
    04586       struct ast_channel *tmpchan;
    04587       tmpchan = ast_channel_alloc(0);
    04588       if (tmpchan) {
    04589          snprintf(tmpchan->name, sizeof(tmpchan->name), "AsyncGoto/%s", chan->name);
    04590          ast_setstate(tmpchan, chan->_state);
    04591          /* Make formats okay */
    04592          tmpchan->readformat = chan->readformat;
    04593          tmpchan->writeformat = chan->writeformat;
    04594          /* Setup proper location */
    04595          ast_explicit_goto(tmpchan,
    04596                  (!ast_strlen_zero(context)) ? context : chan->context,
    04597                  (!ast_strlen_zero(exten)) ? exten : chan->exten,
    04598                  priority);
    04599
    04600          /* Masquerade into temp channel */
    04601          ast_channel_masquerade(tmpchan, chan);
    04602
    04603          /* Grab the locks and get going */
    04604          ast_mutex_lock(&tmpchan->lock);
    04605          ast_do_masquerade(tmpchan);
    04606          ast_mutex_unlock(&tmpchan->lock);
    04607          /* Start the PBX going on our stolen channel */
    04608          if (ast_pbx_start(tmpchan)) {
    04609             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
    04610             ast_hangup(tmpchan);
    04611             res = -1;
    04612          }
    04613       } else {
    04614          res = -1;
    04615       }
    04616    }
    04617    ast_mutex_unlock(&chan->lock);
    04618    return res;
    04619 }
    04620
    04621 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
    04622 {
    04623    struct ast_channel *chan;
    04624    int res = -1;
    04625
    04626    chan = ast_get_channel_by_name_locked(channame);
    04627    if (chan) {
    04628       res = ast_async_goto(chan, context, exten, priority);
    04629       ast_mutex_unlock(&chan->lock);
    04630    }
    04631    return res;
    04632 }
    04633
    04634 static int ext_strncpy(char *dst, const char *src, int len)
    04635 {
    04636    int count=0;
    04637
    04638    while(*src && (count < len - 1)) {
    04639       switch(*src) {
    04640       case ' ':
    04641          /* otherwise exten => [a-b],1,... doesn't work */
    04642          /*    case '-': */
    04643          /* Ignore */
    04644          break;
    04645       default:
    04646          *dst = *src;
    04647          dst++;
    04648       }
    04649       src++;
    04650       count++;
    04651    }
    04652    *dst = '\0';
    04653
    04654    return count;
    04655 }
    04656
    04657 static void null_datad(void *foo)
    04658 {
    04659 }
    04660
    04661 /*
    04662  * EBUSY - can't lock
    04663  * EEXIST - extension with the same priority exist and no replace is set
    04664  *
    04665  */
    04666 int ast_add_extension2(struct ast_context *con,
    04667                  int replace, const char *extension, int priority, const char *label, const char *callerid,
    04668                  const char *application, void *data, void (*datad)(void *),
    04669                  const char *registrar)
    04670 {
    04671
    04672 #define LOG do {  if (option_debug) {\
    04673       if (tmp->matchcid) { \
    04674          ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
    04675       } else { \
    04676          ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
    04677       } \
    04678    } \
    04679    if (option_verbose > 2) { \
    04680       if (tmp->matchcid) { \
    04681          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n", tmp->exten, tmp->priority, tmp->cidmatch, con->name); \
    04682       } else {  \
    04683          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n", tmp->exten, tmp->priority, con->name); \
    04684       } \
    04685    } } while(0)
    04686
    04687    /*
    04688     * This is a fairly complex routine.  Different extensions are kept
    04689     * in order by the extension number.  Then, extensions of different
    04690     * priorities (same extension) are kept in a list, according to the
    04691     * peer pointer.
    04692     */
    04693    struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
    04694    int res;
    04695    int length;
    04696    char *p;
    04697    char expand_buf[VAR_BUF_SIZE] = { 0, };
    04698
    04699    /* if we are adding a hint, and there are global variables, and the hint
    04700       contains variable references, then expand them
    04701    */
    04702    ast_mutex_lock(&globalslock);
    04703    if ((priority == PRIORITY_HINT) && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
    04704       pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
    04705       application = expand_buf;
    04706    }
    04707    ast_mutex_unlock(&globalslock);
    04708
    04709    length = sizeof(struct ast_exten);
    04710    length += strlen(extension) + 1;
    04711    length += strlen(application) + 1;
    04712    if (label)
    04713       length += strlen(label) + 1;
    04714    if (callerid)
    04715       length += strlen(callerid) + 1;
    04716    else
    04717       length ++;
    04718
    04719    /* Be optimistic:  Build the extension structure first */
    04720    if (datad == NULL)
    04721       datad = null_datad;
    04722    tmp = malloc(length);
    04723    if (tmp) {
    04724       memset(tmp, 0, length);
    04725       p = tmp->stuff;
    04726       if (label) {
    04727          tmp->label = p;
    04728          strcpy(tmp->label, label);
    04729          p += strlen(label) + 1;
    04730       }
    04731       tmp->exten = p;
    04732       p += ext_strncpy(tmp->exten, extension, strlen(extension) + 1) + 1;
    04733       tmp->priority = priority;
    04734       tmp->cidmatch = p;
    04735       if (callerid) {
    04736          p += ext_strncpy(tmp->cidmatch, callerid, strlen(callerid) + 1) + 1;
    04737          tmp->matchcid = 1;
    04738       } else {
    04739          tmp->cidmatch[0] = '\0';
    04740          tmp->matchcid = 0;
    04741          p++;
    04742       }
    04743       tmp->app = p;
    04744       strcpy(tmp->app, application);
    04745       tmp->parent = con;
    04746       tmp->data = data;
    04747       tmp->datad = datad;
    04748       tmp->registrar = registrar;
    04749       tmp->peer = NULL;
    04750       tmp->next =  NULL;
    04751    } else {
    04752       ast_log(LOG_ERROR, "Out of memory\n");
    04753       errno = ENOMEM;
    04754       return -1;
    04755    }
    04756    if (ast_mutex_lock(&con->lock)) {
    04757       free(tmp);
    04758       /* And properly destroy the data */
    04759       datad(data);
    04760       ast_log(LOG_WARNING, "Failed to lock context '%s'\n", con->name);
    04761       errno = EBUSY;
    04762       return -1;
    04763    }
    04764    e = con->root;
    04765    while(e) {
    04766       /* Make sure patterns are always last! */
    04767       if ((e->exten[0] != '_') && (extension[0] == '_'))
    04768          res = -1;
    04769       else if ((e->exten[0] == '_') && (extension[0] != '_'))
    04770          res = 1;
    04771       else
    04772          res= strcmp(e->exten, extension);
    04773       if (!res) {
    04774          if (!e->matchcid && !tmp->matchcid)
    04775             res = 0;
    04776          else if (tmp->matchcid && !e->matchcid)
    04777             res = 1;
    04778          else if (e->matchcid && !tmp->matchcid)
    04779             res = -1;
    04780          else
    04781             res = strcasecmp(e->cidmatch, tmp->cidmatch);
    04782       }
    04783       if (res == 0) {
    04784          /* We have an exact match, now we find where we are
    04785             and be sure there's no duplicates */
    04786          while(e) {
    04787             if (e->priority == tmp->priority) {
    04788                /* Can't have something exactly the same.  Is this a
    04789                   replacement?  If so, replace, otherwise, bonk. */
    04790                if (replace) {
    04791                   if (ep) {
    04792                      /* We're in the peer list, insert ourselves */
    04793                      ep->peer = tmp;
    04794                      tmp->peer = e->peer;
    04795                   } else if (el) {
    04796                      /* We're the first extension. Take over e's functions */
    04797                      el->next = tmp;
    04798                      tmp->next = e->next;
    04799                      tmp->peer = e->peer;
    04800                   } else {
    04801                      /* We're the very first extension.  */
    04802                      con->root = tmp;
    04803                      tmp->next = e->next;
    04804                      tmp->peer = e->peer;
    04805                   }
    04806                   if (tmp->priority == PRIORITY_HINT)
    04807                       ast_change_hint(e,tmp);
    04808                   /* Destroy the old one */
    04809                   e->datad(e->data);
    04810                   free(e);
    04811                   ast_mutex_unlock(&con->lock);
    04812                   if (tmp->priority == PRIORITY_HINT)
    04813                       ast_change_hint(e, tmp);
    04814                   /* And immediately return success. */
    04815                   LOG;
    04816                   return 0;
    04817                } else {
    04818                   ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
    04819                   tmp->datad(tmp->data);
    04820                   free(tmp);
    04821                   ast_mutex_unlock(&con->lock);
    04822                   errno = EEXIST;
    04823                   return -1;
    04824                }
    04825             } else if (e->priority > tmp->priority) {
    04826                /* Slip ourselves in just before e */
    04827                if (ep) {
    04828                   /* Easy enough, we're just in the peer list */
    04829                   ep->peer = tmp;
    04830                   tmp->peer = e;
    04831                } else if (el) {
    04832                   /* We're the first extension in this peer list */
    04833                   el->next = tmp;
    04834                   tmp->next = e->next;
    04835                   e->next = NULL;
    04836                   tmp->peer = e;
    04837                } else {
    04838                   /* We're the very first extension altogether */
    04839                   tmp->next = con->root->next;
    04840                   /* Con->root must always exist or we couldn't get here */
    04841                   tmp->peer = con->root;
    04842                   con->root = tmp;
    04843                }
    04844                ast_mutex_unlock(&con->lock);
    04845
    04846                /* And immediately return success. */
    04847                if (tmp->priority == PRIORITY_HINT)
    04848                    ast_add_hint(tmp);
    04849
    04850                LOG;
    04851                return 0;
    04852             }
    04853             ep = e;
    04854             e = e->peer;
    04855          }
    04856          /* If we make it here, then it's time for us to go at the very end.
    04857             ep *must* be defined or we couldn't have gotten here. */
    04858          ep->peer = tmp;
    04859          ast_mutex_unlock(&con->lock);
    04860          if (tmp->priority == PRIORITY_HINT)
    04861             ast_add_hint(tmp);
    04862
    04863          /* And immediately return success. */
    04864          LOG;
    04865          return 0;
    04866
    04867       } else if (res > 0) {
    04868          /* Insert ourselves just before 'e'.  We're the first extension of
    04869             this kind */
    04870          tmp->next = e;
    04871          if (el) {
    04872             /* We're in the list somewhere */
    04873             el->next = tmp;
    04874          } else {
    04875             /* We're at the top of the list */
    04876             con->root = tmp;
    04877          }
    04878          ast_mutex_unlock(&con->lock);
    04879          if (tmp->priority == PRIORITY_HINT)
    04880             ast_add_hint(tmp);
    04881
    04882          /* And immediately return success. */
    04883          LOG;
    04884          return 0;
    04885       }
    04886
    04887       el = e;
    04888       e = e->next;
    04889    }
    04890    /* If we fall all the way through to here, then we need to be on the end. */
    04891    if (el)
    04892       el->next = tmp;
    04893    else
    04894       con->root = tmp;
    04895    ast_mutex_unlock(&con->lock);
    04896    if (tmp->priority == PRIORITY_HINT)
    04897       ast_add_hint(tmp);
    04898    LOG;
    04899    return 0;
    04900 }
    04901
    04902 struct async_stat {
    04903    pthread_t p;
    04904    struct ast_channel *chan;
    04905    char context[AST_MAX_CONTEXT];
    04906    char exten[AST_MAX_EXTENSION];
    04907    int priority;
    04908    int timeout;
    04909    char app[AST_MAX_EXTENSION];
    04910    char appdata[1024];
    04911 };
    04912
    04913 static void *async_wait(void *data)
    04914 {
    04915    struct async_stat *as = data;
    04916    struct ast_channel *chan = as->chan;
    04917    int timeout = as->timeout;
    04918    int res;
    04919    struct ast_frame *f;
    04920    struct ast_app *app;
    04921
    04922    while(timeout && (chan->_state != AST_STATE_UP)) {
    04923       res = ast_waitfor(chan, timeout);
    04924       if (res < 1)
    04925          break;
    04926       if (timeout > -1)
    04927          timeout = res;
    04928       f = ast_read(chan);
    04929       if (!f)
    04930          break;
    04931       if (f->frametype == AST_FRAME_CONTROL) {
    04932          if ((f->subclass == AST_CONTROL_BUSY)  ||
    04933              (f->subclass == AST_CONTROL_CONGESTION) ) {
    04934             ast_frfree(f);
    04935             break;
    04936          }
    04937       }
    04938       ast_frfree(f);
    04939    }
    04940    if (chan->_state == AST_STATE_UP) {
    04941       if (!ast_strlen_zero(as->app)) {
    04942          app = pbx_findapp(as->app);
    04943          if (app) {
    04944             if (option_verbose > 2)
    04945                ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
    04946             pbx_exec(chan, app, as->appdata, 1);
    04947          } else
    04948             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
    04949       } else {
    04950          if (!ast_strlen_zero(as->context))
    04951             ast_copy_string(chan->context, as->context, sizeof(chan->context));
    04952          if (!ast_strlen_zero(as->exten))
    04953             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
    04954          if (as->priority > 0)
    04955             chan->priority = as->priority;
    04956          /* Run the PBX */
    04957          if (ast_pbx_run(chan)) {
    04958             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
    04959          } else {
    04960             /* PBX will have taken care of this */
    04961             chan = NULL;
    04962          }
    04963       }
    04964
    04965    }
    04966    free(as);
    04967    if (chan)
    04968       ast_hangup(chan);
    04969    return NULL;
    04970 }
    04971
    04972 /*! Function to post an empty cdr after a spool call fails.
    04973  *
    04974  *  This function posts an empty cdr for a failed spool call
    04975  *
    04976  */
    04977 int ast_pbx_outgoing_cdr_failed(void)
    04978 {
    04979    /* allocate a channel */
    04980    struct ast_channel *chan = ast_channel_alloc(0);
    04981    if(!chan) {
    04982       /* allocation of the channel failed, let some peeps know */
    04983       ast_log(LOG_WARNING, "Unable to allocate channel structure for CDR record\n");
    04984       return -1;  /* failure */
    04985    }
    04986
    04987    chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
    04988
    04989    if(!chan->cdr) {
    04990       /* allocation of the cdr failed */
    04991       ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
    04992       ast_channel_free(chan);   /* free the channel */
    04993       return -1;                /* return failure */
    04994    }
    04995
    04996    /* allocation of the cdr was successful */
    04997    ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
    04998    ast_cdr_start(chan->cdr);       /* record the start and stop time */
    04999    ast_cdr_end(chan->cdr);
    05000    ast_cdr_failed(chan->cdr);      /* set the status to failed */
    05001    ast_cdr_detach(chan->cdr);      /* post and free the record */
    05002    ast_channel_free(chan);         /* free the channel */
    05003
    05004    return 0;  /* success */
    05005 }
    05006
    05007 int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
    05008 {
    05009    struct ast_channel *chan;
    05010    struct async_stat *as;
    05011    int res = -1, cdr_res = -1;
    05012    struct outgoing_helper oh;
    05013    pthread_attr_t attr;
    05014
    05015    if (sync) {
    05016       LOAD_OH(oh);
    05017       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
    05018       if (channel) {
    05019          *channel = chan;
    05020          if (chan)
    05021             ast_mutex_lock(&chan->lock);
    05022       }
    05023       if (chan) {
    05024          if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
    05025             ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
    05026          } else {
    05027             chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
    05028             if (!chan->cdr) {
    05029                /* allocation of the cdr failed */
    05030                ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
    05031                free(chan->pbx);
    05032                res = -1;
    05033                goto outgoing_exten_cleanup;
    05034             }
    05035             /* allocation of the cdr was successful */
    05036             ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
    05037             ast_cdr_start(chan->cdr);
    05038          }
    05039          if (chan->_state == AST_STATE_UP) {
    05040                res = 0;
    05041             if (option_verbose > 3)
    05042                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
    05043
    05044             if (sync > 1) {
    05045                if (channel)
    05046                   ast_mutex_unlock(&chan->lock);
    05047                if (ast_pbx_run(chan)) {
    05048                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
    05049                   if (channel)
    05050                      *channel = NULL;
    05051                   ast_hangup(chan);
    05052                   res = -1;
    05053                }
    05054             } else {
    05055                if (ast_pbx_start(chan)) {
    05056                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
    05057                   if (channel) {
    05058                      *channel = NULL;
    05059                      ast_mutex_unlock(&chan->lock);
    05060                   }
    05061                   ast_hangup(chan);
    05062                   res = -1;
    05063                }
    05064             }
    05065          } else {
    05066             if (option_verbose > 3)
    05067                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
    05068
    05069             if(chan->cdr) { /* update the cdr */
    05070                /* here we update the status of the call, which sould be busy.
    05071                 * if that fails then we set the status to failed */
    05072                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
    05073                   ast_cdr_failed(chan->cdr);
    05074             }
    05075
    05076             if (channel) {
    05077                *channel = NULL;
    05078                ast_mutex_unlock(&chan->lock);
    05079             }
    05080             ast_hangup(chan);
    05081          }
    05082       }
    05083
    05084       if (res < 0) { /* the call failed for some reason */
    05085          if (*reason == 0) { /* if the call failed (not busy or no answer)
    05086                         * update the cdr with the failed message */
    05087             cdr_res = ast_pbx_outgoing_cdr_failed();
    05088             if (cdr_res != 0) {
    05089                res = cdr_res;
    05090                goto outgoing_exten_cleanup;
    05091             }
    05092          }
    05093
    05094          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
    05095          /* check if "failed" exists */
    05096          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
    05097             chan = ast_channel_alloc(0);
    05098             if (chan) {
    05099                ast_copy_string(chan->name, "OutgoingSpoolFailed", sizeof(chan->name));
    05100                if (!ast_strlen_zero(context))
    05101                   ast_copy_string(chan->context, context, sizeof(chan->context));
    05102                ast_copy_string(chan->exten, "failed", sizeof(chan->exten));
    05103                chan->priority = 1;
    05104                ast_set_variables(chan, vars);
    05105                if (account)
    05106                   ast_cdr_setaccount(chan, account);
    05107                ast_pbx_run(chan);
    05108             } else
    05109                ast_log(LOG_WARNING, "Can't allocate the channel structure, skipping execution of extension 'failed'\n");
    05110          }
    05111       }
    05112    } else {
    05113       as = malloc(sizeof(struct async_stat));
    05114       if (!as) {
    05115          res = -1;
    05116          goto outgoing_exten_cleanup;
    05117       }
    05118       memset(as, 0, sizeof(struct async_stat));
    05119       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
    05120       if (channel) {
    05121          *channel = chan;
    05122          if (chan)
    05123             ast_mutex_lock(&chan->lock);
    05124       }
    05125       if (!chan) {
    05126          free(as);
    05127          res = -1;
    05128          goto outgoing_exten_cleanup;
    05129       }
    05130       as->chan = chan;
    05131       ast_copy_string(as->context, context, sizeof(as->context));
    05132       ast_copy_string(as->exten,  exten, sizeof(as->exten));
    05133       as->priority = priority;
    05134       as->timeout = timeout;
    05135       ast_set_variables(chan, vars);
    05136       if (account)
    05137          ast_cdr_setaccount(chan, account);
    05138       pthread_attr_init(&attr);
    05139       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    05140       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
    05141          ast_log(LOG_WARNING, "Failed to start async wait\n");
    05142          free(as);
    05143          if (channel) {
    05144             *channel = NULL;
    05145             ast_mutex_unlock(&chan->lock);
    05146          }
    05147          ast_hangup(chan);
    05148          res = -1;
    05149          pthread_attr_destroy(&attr);
    05150          goto outgoing_exten_cleanup;
    05151       }
    05152       pthread_attr_destroy(&attr);
    05153       res = 0;
    05154    }
    05155 outgoing_exten_cleanup:
    05156    ast_variables_destroy(vars);
    05157    return res;
    05158 }
    05159
    05160 struct app_tmp {
    05161    char app[256];
    05162    char data[256];
    05163    struct ast_channel *chan;
    05164    pthread_t t;
    05165 };
    05166
    05167 static void *ast_pbx_run_app(void *data)
    05168 {
    05169    struct app_tmp *tmp = data;
    05170    struct ast_app *app;
    05171    app = pbx_findapp(tmp->app);
    05172    if (app) {
    05173       if (option_verbose > 3)
    05174          ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
    05175       pbx_exec(tmp->chan, app, tmp->data, 1);
    05176    } else
    05177       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
    05178    ast_hangup(tmp->chan);
    05179    free(tmp);
    05180    return NULL;
    05181 }
    05182
    05183 int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
    05184 {
    05185    struct ast_channel *chan;
    05186    struct async_stat *as;
    05187    struct app_tmp *tmp;
    05188    int res = -1, cdr_res = -1;
    05189    struct outgoing_helper oh;
    05190    pthread_attr_t attr;
    05191
    05192    memset(&oh, 0, sizeof(oh));
    05193    oh.vars = vars;
    05194    oh.account = account;
    05195
    05196    if (locked_channel)
    05197       *locked_channel = NULL;
    05198    if (ast_strlen_zero(app)) {
    05199       res = -1;
    05200       goto outgoing_app_cleanup;
    05201    }
    05202    if (sync) {
    05203       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
    05204       if (chan) {
    05205          if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
    05206             ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
    05207          } else {
    05208             chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
    05209             if(!chan->cdr) {
    05210                /* allocation of the cdr failed */
    05211                ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
    05212                free(chan->pbx);
    05213                res = -1;
    05214                goto outgoing_app_cleanup;
    05215             }
    05216             /* allocation of the cdr was successful */
    05217             ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
    05218             ast_cdr_start(chan->cdr);
    05219          }
    05220          ast_set_variables(chan, vars);
    05221          if (account)
    05222             ast_cdr_setaccount(chan, account);
    05223          if (chan->_state == AST_STATE_UP) {
    05224             res = 0;
    05225             if (option_verbose > 3)
    05226                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
    05227             tmp = malloc(sizeof(struct app_tmp));
    05228             if (tmp) {
    05229                memset(tmp, 0, sizeof(struct app_tmp));
    05230                ast_copy_string(tmp->app, app, sizeof(tmp->app));
    05231                if (appdata)
    05232                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
    05233                tmp->chan = chan;
    05234                if (sync > 1) {
    05235                   if (locked_channel)
    05236                      ast_mutex_unlock(&chan->lock);
    05237                   ast_pbx_run_app(tmp);
    05238                } else {
    05239                   pthread_attr_init(&attr);
    05240                   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    05241                   if (locked_channel)
    05242                      ast_mutex_lock(&chan->lock);
    05243                   if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
    05244                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
    05245                      free(tmp);
    05246                      if (locked_channel)
    05247                         ast_mutex_unlock(&chan->lock);
    05248                      ast_hangup(chan);
    05249                      res = -1;
    05250                   } else {
    05251                      if (locked_channel)
    05252                         *locked_channel = chan;
    05253                   }
    05254                   pthread_attr_destroy(&attr);
    05255                }
    05256             } else {
    05257                ast_log(LOG_ERROR, "Out of memory :(\n");
    05258                res = -1;
    05259             }
    05260          } else {
    05261             if (option_verbose > 3)
    05262                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
    05263             if (chan->cdr) { /* update the cdr */
    05264                /* here we update the status of the call, which sould be busy.
    05265                 * if that fails then we set the status to failed */
    05266                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
    05267                   ast_cdr_failed(chan->cdr);
    05268             }
    05269             ast_hangup(chan);
    05270          }
    05271       }
    05272
    05273       if (res < 0) { /* the call failed for some reason */
    05274          if (*reason == 0) { /* if the call failed (not busy or no answer)
    05275                         * update the cdr with the failed message */
    05276             cdr_res = ast_pbx_outgoing_cdr_failed();
    05277             if (cdr_res != 0) {
    05278                res = cdr_res;
    05279                goto outgoing_app_cleanup;
    05280             }
    05281          }
    05282       }
    05283
    05284    } else {
    05285       as = malloc(sizeof(struct async_stat));
    05286       if (!as) {
    05287          res = -1;
    05288          goto outgoing_app_cleanup;
    05289       }
    05290       memset(as, 0, sizeof(struct async_stat));
    05291       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
    05292       if (!chan) {
    05293          free(as);
    05294          res = -1;
    05295          goto outgoing_app_cleanup;
    05296       }
    05297       as->chan = chan;
    05298       ast_copy_string(as->app, app, sizeof(as->app));
    05299       if (appdata)
    05300          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
    05301       as->timeout = timeout;
    05302       ast_set_variables(chan, vars);
    05303       if (account)
    05304          ast_cdr_setaccount(chan, account);
    05305       /* Start a new thread, and get something handling this channel. */
    05306       pthread_attr_init(&attr);
    05307       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    05308       if (locked_channel)
    05309          ast_mutex_lock(&chan->lock);
    05310       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
    05311          ast_log(LOG_WARNING, "Failed to start async wait\n");
    05312          free(as);
    05313          if (locked_channel)
    05314             ast_mutex_unlock(&chan->lock);
    05315          ast_hangup(chan);
    05316          res = -1;
    05317          pthread_attr_destroy(&attr);
    05318          goto outgoing_app_cleanup;
    05319       } else {
    05320          if (locked_channel)
    05321             *locked_channel = chan;
    05322       }
    05323       pthread_attr_destroy(&attr);
    05324       res = 0;
    05325    }
    05326 outgoing_app_cleanup:
    05327    ast_variables_destroy(vars);
    05328    return res;
    05329 }
    05330
    05331 static void destroy_exten(struct ast_exten *e)
    05332 {
    05333    if (e->priority == PRIORITY_HINT)
    05334       ast_remove_hint(e);
    05335
    05336    if (e->datad)
    05337       e->datad(e->data);
    05338    free(e);
    05339 }
    05340
    05341 void __ast_context_destroy(struct ast_context *con, const char *registrar)
    05342 {
    05343    struct ast_context *tmp, *tmpl=NULL;
    05344    struct ast_include *tmpi, *tmpil= NULL;
    05345    struct ast_sw *sw, *swl= NULL;
    05346    struct ast_exten *e, *el, *en;
    05347    struct ast_ignorepat *ipi, *ipl = NULL;
    05348
    05349    ast_mutex_lock(&conlock);
    05350    tmp = contexts;
    05351    while(tmp) {
    05352       if (((tmp->name && con && con->name && !strcasecmp(tmp->name, con->name)) || !con) &&
    05353           (!registrar || !strcasecmp(registrar, tmp->registrar))) {
    05354          /* Okay, let's lock the structure to be sure nobody else
    05355             is searching through it. */
    05356          if (ast_mutex_lock(&tmp->lock)) {
    05357             ast_log(LOG_WARNING, "Unable to lock context lock\n");
    05358             return;
    05359          }
    05360          if (tmpl)
    05361             tmpl->next = tmp->next;
    05362          else
    05363             contexts = tmp->next;
    05364          /* Okay, now we're safe to let it go -- in a sense, we were
    05365             ready to let it go as soon as we locked it. */
    05366          ast_mutex_unlock(&tmp->lock);
    05367          for (tmpi = tmp->includes; tmpi; ) {
    05368             /* Free includes */
    05369             tmpil = tmpi;
    05370             tmpi = tmpi->next;
    05371             free(tmpil);
    05372          }
    05373          for (ipi = tmp->ignorepats; ipi; ) {
    05374             /* Free ignorepats */
    05375             ipl = ipi;
    05376             ipi = ipi->next;
    05377             free(ipl);
    05378          }
    05379          for (sw = tmp->alts; sw; ) {
    05380             /* Free switches */
    05381             swl = sw;
    05382             sw = sw->next;
    05383             free(swl);
    05384             swl = sw;
    05385          }
    05386          for (e = tmp->root; e;) {
    05387             for (en = e->peer; en;) {
    05388                el = en;
    05389                en = en->peer;
    05390                destroy_exten(el);
    05391             }
    05392             el = e;
    05393             e = e->next;
    05394             destroy_exten(el);
    05395          }
    05396          ast_mutex_destroy(&tmp->lock);
    05397          free(tmp);
    05398          if (!con) {
    05399             /* Might need to get another one -- restart */
    05400             tmp = contexts;
    05401             tmpl = NULL;
    05402             tmpil = NULL;
    05403             continue;
    05404          }
    05405          ast_mutex_unlock(&conlock);
    05406          return;
    05407       }
    05408       tmpl = tmp;
    05409       tmp = tmp->next;
    05410    }
    05411    ast_mutex_unlock(&conlock);
    05412 }
    05413
    05414 void ast_context_destroy(struct ast_context *con, const char *registrar)
    05415 {
    05416    __ast_context_destroy(con,registrar);
    05417 }
    05418
    05419 static void wait_for_hangup(struct ast_channel *chan, void *data)
    05420 {
    05421    int res;
    05422    struct ast_frame *f;
    05423    int waittime;
    05424
    05425    if (ast_strlen_zero(data) || (sscanf(data, "%30d", &waittime) != 1) || (waittime < 0))
    05426       waittime = -1;
    05427    if (waittime > -1) {
    05428       ast_safe_sleep(chan, waittime * 1000);
    05429    } else do {
    05430       res = ast_waitfor(chan, -1);
    05431       if (res < 0)
    05432          return;
    05433       f = ast_read(chan);
    05434       if (f)
    05435          ast_frfree(f);
    05436    } while(f);
    05437 }
    05438
    05439 /*!
    05440  * \ingroup applications
    05441  */
    05442 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
    05443 {
    05444    ast_indicate(chan, AST_CONTROL_PROGRESS);
    05445    return 0;
    05446 }
    05447
    05448 /*!
    05449  * \ingroup applications
    05450  */
    05451 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
    05452 {
    05453    ast_indicate(chan, AST_CONTROL_RINGING);
    05454    return 0;
    05455 }
    05456
    05457 /*!
    05458  * \ingroup applications
    05459  */
    05460 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
    05461 {
    05462    ast_indicate(chan, AST_CONTROL_BUSY);
    05463    if (chan->_state != AST_STATE_UP)
    05464       ast_setstate(chan, AST_STATE_BUSY);
    05465    wait_for_hangup(chan, data);
    05466    return -1;
    05467 }
    05468
    05469 /*!
    05470  * \ingroup applications
    05471  */
    05472 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
    05473 {
    05474    ast_indicate(chan, AST_CONTROL_CONGESTION);
    05475    if (chan->_state != AST_STATE_UP)
    05476       ast_setstate(chan, AST_STATE_BUSY);
    05477    wait_for_hangup(chan, data);
    05478    return -1;
    05479 }
    05480
    05481 /*!
    05482  * \ingroup applications
    05483  */
    05484 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
    05485 {
    05486    int delay = 0;
    05487    int res;
    05488
    05489    if (chan->_state == AST_STATE_UP)
    05490       delay = 0;
    05491    else if (!ast_strlen_zero(data))
    05492       delay = atoi(data);
    05493
    05494    res = ast_answer(chan);
    05495    if (res)
    05496       return res;
    05497
    05498    if (delay)
    05499       res = ast_safe_sleep(chan, delay);
    05500
    05501    return res;
    05502 }
    05503
    05504 /*!
    05505  * \ingroup applications
    05506  */
    05507 static int pbx_builtin_setlanguage(struct ast_channel *chan, void *data)
    05508 {
    05509    static int deprecation_warning = 0;
    05510
    05511    if (!deprecation_warning) {
    05512       ast_log(LOG_WARNING, "SetLanguage is deprecated, please use Set(LANGUAGE()=language) instead.\n");
    05513       deprecation_warning = 1;
    05514    }
    05515
    05516    /* Copy the language as specified */
    05517    if (!ast_strlen_zero(data))
    05518       ast_copy_string(chan->language, data, sizeof(chan->language));
    05519
    05520    return 0;
    05521 }
    05522
    05523 AST_APP_OPTIONS(resetcdr_opts, {
    05524    AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
    05525    AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
    05526    AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
    05527 });
    05528
    05529 /*!
    05530  * \ingroup applications
    05531  */
    05532 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
    05533 {
    05534    char *args;
    05535    struct ast_flags flags = { 0 };
    05536
    05537    if (!ast_strlen_zero(data)) {
    05538       args = ast_strdupa(data);
    05539       if (!args) {
    05540          ast_log(LOG_ERROR, "Out of memory!\n");
    05541          return -1;
    05542       }
    05543       ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
    05544    }
    05545
    05546    ast_cdr_reset(chan->cdr, &flags);
    05547
    05548    return 0;
    05549 }
    05550
    05551 /*!
    05552  * \ingroup applications
    05553  */
    05554 static int pbx_builtin_setaccount(struct ast_channel *chan, void *data)
    05555 {
    05556    /* Copy the account code  as specified */
    05557    if (data)
    05558       ast_cdr_setaccount(chan, (char *)data);
    05559    else
    05560       ast_cdr_setaccount(chan, "");
    05561    return 0;
    05562 }
    05563
    05564 /*!
    05565  * \ingroup applications
    05566  */
    05567 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
    05568 {
    05569    /* Copy the AMA Flags as specified */
    05570    if (data)
    05571       ast_cdr_setamaflags(chan, (char *)data);
    05572    else
    05573       ast_cdr_setamaflags(chan, "");
    05574    return 0;
    05575 }
    05576
    05577 /*!
    05578  * \ingroup applications
    05579  */
    05580 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
    05581 {
    05582    /* Just return non-zero and it will hang up */
    05583    if (!chan->hangupcause)
    05584       chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
    05585    return -1;
    05586 }
    05587
    05588 /*!
    05589  * \ingroup applications
    05590  */
    05591 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
    05592 {
    05593    int res=0;
    05594    char *s, *ts;
    05595    struct ast_timing timing;
    05596
    05597    if (ast_strlen_zero(data)) {
    05598       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
    05599       return -1;
    05600    }
    05601
    05602    if ((s = ast_strdupa((char *) data))) {
    05603       ts = s;
    05604
    05605       /* Separate the Goto path */
    05606       strsep(&ts,"?");
    05607
    05608       /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
    05609       if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
    05610          res = pbx_builtin_goto(chan, (void *)ts);
    05611    } else {
    05612       ast_log(LOG_ERROR, "Memory Error!\n");
    05613    }
    05614    return res;
    05615 }
    05616
    05617 /*!
    05618  * \ingroup applications
    05619  */
    05620 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
    05621 {
    05622    int res = 0;
    05623    char *ptr1, *ptr2;
    05624    struct ast_timing timing;
    05625    struct ast_app *app;
    05626    const char *usage = "ExecIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
    05627
    05628    if (ast_strlen_zero(data)) {
    05629       ast_log(LOG_WARNING, "%s\n", usage);
    05630       return -1;
    05631    }
    05632
    05633    ptr1 = ast_strdupa(data);
    05634
    05635    if (!ptr1) {
    05636       ast_log(LOG_ERROR, "Out of Memory!\n");
    05637       return -1;
    05638    }
    05639
    05640    ptr2 = ptr1;
    05641    /* Separate the Application data ptr1 is the time spec ptr2 is the app|data */
    05642    strsep(&ptr2,"?");
    05643    if(!ast_build_timing(&timing, ptr1)) {
    05644       ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", ptr1, usage);
    05645       res = -1;
    05646    }
    05647
    05648    if (!res && ast_check_timing(&timing)) {
    05649       if (!ptr2) {
    05650          ast_log(LOG_WARNING, "%s\n", usage);
    05651       }
    05652
    05653       /* ptr2 is now the app name
    05654          we're done with ptr1 now so recycle it and use it to point to the app args */
    05655       if((ptr1 = strchr(ptr2, '|'))) {
    05656          *ptr1 = '\0';
    05657          ptr1++;
    05658       }
    05659
    05660       if ((app = pbx_findapp(ptr2))) {
    05661          res = pbx_exec(chan, app, ptr1 ? ptr1 : "", 1);
    05662       } else {
    05663          ast_log(LOG_WARNING, "Cannot locate application %s\n", ptr2);
    05664          res = -1;
    05665       }
    05666    }
    05667
    05668    return res;
    05669 }
    05670
    05671 /*!
    05672  * \ingroup applications
    05673  */
    05674 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
    05675 {
    05676    int ms;
    05677
    05678    /* Wait for "n" seconds */
    05679    if (data && atof((char *)data)) {
    05680       ms = atof((char *)data) * 1000;
    05681       return ast_safe_sleep(chan, ms);
    05682    }
    05683    return 0;
    05684 }
    05685
    05686 /*!
    05687  * \ingroup applications
    05688  */
    05689 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
    05690 {
    05691    int ms, res, argc;
    05692    char *args;
    05693    char *argv[2];
    05694    char *options = NULL;
    05695    char *timeout = NULL;
    05696    struct ast_flags flags = {0};
    05697    char *opts[1] = { NULL };
    05698
    05699    args = ast_strdupa(data);
    05700
    05701    if ((argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
    05702       if (argc > 0) {
    05703          timeout = argv[0];
    05704          if (argc > 1)
    05705             options = argv[1];
    05706       }
    05707    }
    05708
    05709    if (options)
    05710       ast_app_parse_options(waitexten_opts, &flags, opts, options);
    05711
    05712    if (ast_test_flag(&flags, WAITEXTEN_MOH))
    05713       ast_moh_start(chan, opts[0]);
    05714
    05715    /* Wait for "n" seconds */
    05716    if (timeout && atof((char *)timeout))
    05717       ms = atof((char *)timeout) * 1000;
    05718    else if (chan->pbx)
    05719       ms = chan->pbx->rtimeout * 1000;
    05720    else
    05721       ms = 10000;
    05722    res = ast_waitfordigit(chan, ms);
    05723    if (!res) {
    05724       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
    05725          if (option_verbose > 2)
    05726             ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
    05727       } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
    05728          if (option_verbose > 2)
    05729             ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
    05730          ast_copy_string(chan->exten, "t", sizeof(chan->exten));
    05731          chan->priority = 0;
    05732       } else {
    05733          ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
    05734          res = -1;
    05735       }
    05736    }
    05737
    05738    if (ast_test_flag(&flags, WAITEXTEN_MOH))
    05739       ast_moh_stop(chan);
    05740
    05741    return res;
    05742 }
    05743
    05744 /*!
    05745  * \ingroup applications
    05746  */
    05747 static int pbx_builtin_background(struct ast_channel *chan, void *data)
    05748 {
    05749    int res = 0;
    05750    int argc;
    05751    char *parse;
    05752    char *argv[4];
    05753    char *options = NULL;
    05754    char *filename = NULL;
    05755    char *front = NULL, *back = NULL;
    05756    char *lang = NULL;
    05757    char *context = NULL;
    05758    struct ast_flags flags = {0};
    05759
    05760    parse = ast_strdupa(data);
    05761
    05762    if ((argc = ast_app_separate_args(parse, '|', argv, sizeof(argv) / sizeof(argv[0])))) {
    05763       switch (argc) {
    05764       case 4:
    05765          context = argv[3];
    05766       case 3:
    05767          lang = argv[2];
    05768       case 2:
    05769          options = argv[1];
    05770       case 1:
    05771          filename = argv[0];
    05772          break;
    05773       default:
    05774          ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
    05775          return -1;
    05776       }
    05777    }
    05778
    05779    if (!lang)
    05780       lang = chan->language;
    05781
    05782    if (!context)
    05783       context = chan->context;
    05784
    05785    if (options) {
    05786       if (!strcasecmp(options, "skip"))
    05787          flags.flags = BACKGROUND_SKIP;
    05788       else if (!strcasecmp(options, "noanswer"))
    05789          flags.flags = BACKGROUND_NOANSWER;
    05790       else
    05791          ast_app_parse_options(background_opts, &flags, NULL, options);
    05792    }
    05793
    05794    /* Answer if need be */
    05795    if (chan->_state != AST_STATE_UP) {
    05796       if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
    05797          return 0;
    05798       } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
    05799          res = ast_answer(chan);
    05800       }
    05801    }
    05802
    05803    if (!res) {
    05804       /* Stop anything playing */
    05805       ast_stopstream(chan);
    05806       /* Stream a file */
    05807       front = filename;
    05808       while(!res && front) {
    05809          if((back = strchr(front, '&'))) {
    05810             *back = '\0';
    05811             back++;
    05812          }
    05813          res = ast_streamfile(chan, front, lang);
    05814          if (!res) {
    05815             if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
    05816                res = ast_waitstream(chan, "");
    05817             } else {
    05818                if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
    05819                   res = ast_waitstream_exten(chan, context);
    05820                } else {
    05821                   res = ast_waitstream(chan, AST_DIGIT_ANY);
    05822                }
    05823             }
    05824             ast_stopstream(chan);
    05825          } else {
    05826             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
    05827             res = 0;
    05828             break;
    05829          }
    05830          front = back;
    05831       }
    05832    }
    05833    if (context != chan->context && res) {
    05834       snprintf(chan->exten, sizeof(chan->exten), "%c", res);
    05835       ast_copy_string(chan->context, context, sizeof(chan->context));
    05836       chan->priority = 0;
    05837       return 0;
    05838    } else {
    05839       return res;
    05840    }
    05841 }
    05842
    05843 /*! AbsoluteTimeout
    05844  * \ingroup applications
    05845  * \todo Remove in 1.3 dev
    05846  */
    05847 static int pbx_builtin_atimeout(struct ast_channel *chan, void *data)
    05848 {
    05849    static int deprecation_warning = 0;
    05850    int x = atoi((char *) data);
    05851
    05852    if (!deprecation_warning) {
    05853       ast_log(LOG_WARNING, "AbsoluteTimeout is deprecated, please use Set(TIMEOUT(absolute)=timeout) instead.\n");
    05854       deprecation_warning = 1;
    05855    }
    05856
    05857    /* Set the absolute maximum time how long a call can be connected */
    05858    ast_channel_setwhentohangup(chan,x);
    05859    if (option_verbose > 2)
    05860       ast_verbose( VERBOSE_PREFIX_3 "Set Absolute Timeout to %d\n", x);
    05861    return 0;
    05862 }
    05863
    05864 /*! ResponseTimeout
    05865  * \ingroup applications
    05866  * \todo Remove in 1.3 dev
    05867  */
    05868 static int pbx_builtin_rtimeout(struct ast_channel *chan, void *data)
    05869 {
    05870    static int deprecation_warning = 0;
    05871
    05872    if (!deprecation_warning) {
    05873       ast_log(LOG_WARNING, "ResponseTimeout is deprecated, please use Set(TIMEOUT(response)=timeout) instead.\n");
    05874       deprecation_warning = 1;
    05875    }
    05876
    05877    /* If the channel is not in a PBX, return now */
    05878    if (!chan->pbx)
    05879       return 0;
    05880
    05881    /* Set the timeout for how long to wait between digits */
    05882    chan->pbx->rtimeout = atoi((char *)data);
    05883    if (option_verbose > 2)
    05884       ast_verbose( VERBOSE_PREFIX_3 "Set Response Timeout to %d\n", chan->pbx->rtimeout);
    05885    return 0;
    05886 }
    05887
    05888 /*! DigitTimeout
    05889  * \ingroup applications
    05890  * \todo Remove in 1.3 dev
    05891  */
    05892 static int pbx_builtin_dtimeout(struct ast_channel *chan, void *data)
    05893 {
    05894    static int deprecation_warning = 0;
    05895
    05896    if (!deprecation_warning) {
    05897       ast_log(LOG_WARNING, "DigitTimeout is deprecated, please use Set(TIMEOUT(digit)=timeout) instead.\n");
    05898       deprecation_warning = 1;
    05899    }
    05900
    05901    /* If the channel is not in a PBX, return now */
    05902    if (!chan->pbx)
    05903       return 0;
    05904
    05905    /* Set the timeout for how long to wait between digits */
    05906    chan->pbx->dtimeout = atoi((char *)data);
    05907    if (option_verbose > 2)
    05908       ast_verbose( VERBOSE_PREFIX_3 "Set Digit Timeout to %d\n", chan->pbx->dtimeout);
    05909    return 0;
    05910 }
    05911
    05912 /*! Goto
    05913  * \ingroup applications
    05914  */
    05915 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
    05916 {
    05917    int res;
    05918    res = ast_parseable_goto(chan, (const char *) data);
    05919    if (!res && (option_verbose > 2))
    05920       ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
    05921    return res;
    05922 }
    05923
    05924
    05925 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
    05926 {
    05927    struct ast_var_t *variables;
    05928    char *var, *val;
    05929    int total = 0;
    05930
    05931    if (!chan)
    05932       return 0;
    05933
    05934    memset(buf, 0, size);
    05935
    05936    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
    05937       if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))) {
    05938          if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
    05939             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
    05940             break;
    05941          } else
    05942             total++;
    05943       } else
    05944          break;
    05945    }
    05946
    05947    return total;
    05948 }
    05949
    05950 char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
    05951 {
    05952         struct ast_var_t *variables;
    05953         char *ret = NULL;
    05954         int i;
    05955         struct varshead *places[2] = { NULL, &globals };
    05956
    05957         if (!name)
    05958                 return NULL;
    05959         if (chan)
    05960                 places[0] = &chan->varshead;
    05961
    05962         for (i = 0; i < 2; i++) {
    05963                 if (!places[i])
    05964                         continue;
    05965                 if (places[i] == &globals)
    05966                         ast_mutex_lock(&globalslock);
    05967                 AST_LIST_TRAVERSE(places[i], variables, entries) {
    05968                         if (!strcmp(name, ast_var_name(variables))) {
    05969                                 ret = ast_var_value(variables);
    05970                                 break;
    05971                         }
    05972                 }
    05973                 if (places[i] == &globals)
    05974                         ast_mutex_unlock(&globalslock);
    05975                 if (ret)
    05976                         break;
    05977         }
    05978
    05979         return ret;
    05980 }
    05981
    05982 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
    05983 {
    05984    struct ast_var_t *newvariable;
    05985    struct varshead *headp;
    05986
    05987    if (name[strlen(name)-1] == ')') {
    05988       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
    05989       return ast_func_write(chan, name, value);
    05990    }
    05991
    05992    headp = (chan) ? &chan->varshead : &globals;
    05993
    05994    if (value) {
    05995       if ((option_verbose > 1) && (headp == &globals))
    05996          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
    05997       newvariable = ast_var_assign(name, value);
    05998       if (headp == &globals)
    05999          ast_mutex_lock(&globalslock);
    06000       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    06001       if (headp == &globals)
    06002          ast_mutex_unlock(&globalslock);
    06003    }
    06004 }
    06005
    06006 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
    06007 {
    06008    struct ast_var_t *newvariable;
    06009    struct varshead *headp;
    06010    const char *nametail = name;
    06011
    06012    if (name[strlen(name)-1] == ')')
    06013       return ast_func_write(chan, name, value);
    06014
    06015    headp = (chan) ? &chan->varshead : &globals;
    06016
    06017    /* For comparison purposes, we have to strip leading underscores */
    06018    if (*nametail == '_') {
    06019       nametail++;
    06020       if (*nametail == '_')
    06021          nametail++;
    06022    }
    06023
    06024    if (headp == &globals)
    06025       ast_mutex_lock(&globalslock);
    06026    AST_LIST_TRAVERSE (headp, newvariable, entries) {
    06027       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
    06028          /* there is already such a variable, delete it */
    06029          AST_LIST_REMOVE(headp, newvariable, entries);
    06030          ast_var_delete(newvariable);
    06031          break;
    06032       }
    06033    }
    06034
    06035    if (value) {
    06036       if ((option_verbose > 1) && (headp == &globals))
    06037          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
    06038       newvariable = ast_var_assign(name, value);
    06039       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    06040    }
    06041
    06042    if (headp == &globals)
    06043       ast_mutex_unlock(&globalslock);
    06044 }
    06045
    06046 int pbx_builtin_setvar_old(struct ast_channel *chan, void *data)
    06047 {
    06048    static int deprecation_warning = 0;
    06049
    06050    if (!deprecation_warning) {
    06051       ast_log(LOG_WARNING, "SetVar is deprecated, please use Set instead.\n");
    06052       deprecation_warning = 1;
    06053    }
    06054
    06055    return pbx_builtin_setvar(chan, data);
    06056 }
    06057
    06058 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
    06059 {
    06060    char *name, *value, *mydata;
    06061    int argc;
    06062    char *argv[24];      /* this will only support a maximum of 24 variables being set in a single operation */
    06063    int global = 0;
    06064    int x;
    06065
    06066    if (ast_strlen_zero(data)) {
    06067       ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
    06068       return 0;
    06069    }
    06070
    06071    mydata = ast_strdupa(data);
    06072    argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
    06073
    06074    /* check for a trailing flags argument */
    06075    if ((argc > 1) && !strchr(argv[argc-1], '=')) {
    06076       argc--;
    06077       if (strchr(argv[argc], 'g'))
    06078          global = 1;
    06079    }
    06080
    06081    for (x = 0; x < argc; x++) {
    06082       name = argv[x];
    06083       if ((value = strchr(name, '='))) {
    06084          *value = '\0';
    06085          value++;
    06086          pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
    06087       } else
    06088          ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
    06089    }
    06090
    06091    return(0);
    06092 }
    06093
    06094 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
    06095 {
    06096    char *name;
    06097    char *value;
    06098    char *stringp=NULL;
    06099    char *channel;
    06100    struct ast_channel *chan2;
    06101    char tmp[VAR_BUF_SIZE]="";
    06102    char *s;
    06103
    06104    if (ast_strlen_zero(data)) {
    06105       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
    06106       return 0;
    06107    }
    06108
    06109    stringp = ast_strdupa(data);
    06110    name = strsep(&stringp,"=");
    06111    channel = strsep(&stringp,"|");
    06112    value = strsep(&stringp,"\0");
    06113    if (channel && value && name) {
    06114       chan2 = ast_get_channel_by_name_locked(channel);
    06115       if (chan2) {
    06116          s = alloca(strlen(value) + 4);
    06117          if (s) {
    06118             sprintf(s, "${%s}", value);
    06119             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
    06120          }
    06121          ast_mutex_unlock(&chan2->lock);
    06122       }
    06123       pbx_builtin_setvar_helper(chan, name, tmp);
    06124    }
    06125
    06126    return(0);
    06127 }
    06128
    06129 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
    06130 {
    06131    char *name;
    06132    char *value;
    06133    char *stringp = NULL;
    06134
    06135    if (ast_strlen_zero(data)) {
    06136       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
    06137       return 0;
    06138    }
    06139
    06140    stringp = data;
    06141    name = strsep(&stringp, "=");
    06142    value = strsep(&stringp, "\0");
    06143
    06144    pbx_builtin_setvar_helper(NULL, name, value);
    06145
    06146    return(0);
    06147 }
    06148
    06149 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
    06150 {
    06151    return 0;
    06152 }
    06153
    06154
    06155 void pbx_builtin_clear_globals(void)
    06156 {
    06157    struct ast_var_t *vardata;
    06158
    06159    ast_mutex_lock(&globalslock);
    06160    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
    06161       ast_var_delete(vardata);
    06162    ast_mutex_unlock(&globalslock);
    06163 }
    06164
    06165 int pbx_checkcondition(char *condition)
    06166 {
    06167    if (condition) {
    06168       if (*condition == '\0') {
    06169          /* Empty strings are false */
    06170          return 0;
    06171       } else if (*condition >= '0' && *condition <= '9') {
    06172          /* Numbers are evaluated for truth */
    06173          return atoi(condition);
    06174       } else {
    06175          /* Strings are true */
    06176          return 1;
    06177       }
    06178    } else {
    06179       /* NULL is also false */
    06180       return 0;
    06181    }
    06182 }
    06183
    06184 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
    06185 {
    06186    char *condition, *branch1, *branch2, *branch;
    06187    char *s;
    06188    int rc;
    06189    char *stringp=NULL;
    06190
    06191    if (ast_strlen_zero(data)) {
    06192       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
    06193       return 0;
    06194    }
    06195
    06196    s = ast_strdupa(data);
    06197    stringp = s;
    06198    condition = strsep(&stringp,"?");
    06199    branch1 = strsep(&stringp,":");
    06200    branch2 = strsep(&stringp,"");
    06201    branch = pbx_checkcondition(condition) ? branch1 : branch2;
    06202
    06203    if (ast_strlen_zero(branch)) {
    06204       ast_log(LOG_DEBUG, "Not taking any branch\n");
    06205       return 0;
    06206    }
    06207
    06208    rc = pbx_builtin_goto(chan, branch);
    06209
    06210    return rc;
    06211 }
    06212
    06213 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
    06214 {
    06215    int res = 0;
    06216    char tmp[256];
    06217    char *number = (char *) NULL;
    06218    char *options = (char *) NULL;
    06219
    06220
    06221    if (ast_strlen_zero(data)) {
    06222       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
    06223       return -1;
    06224    }
    06225    ast_copy_string(tmp, (char *) data, sizeof(tmp));
    06226    number=tmp;
    06227    strsep(&number, "|");
    06228    options = strsep(&number, "|");
    06229    if (options) {
    06230       if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
    06231          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
    06232          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
    06233          return -1;
    06234       }
    06235    }
    06236    return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options);
    06237 }
    06238
    06239 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
    06240 {
    06241    int res = 0;
    06242
    06243    if (data)
    06244       res = ast_say_digit_str(chan, (char *)data, "", chan->language);
    06245    return res;
    06246 }
    06247
    06248 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
    06249 {
    06250    int res = 0;
    06251
    06252    if (data)
    06253       res = ast_say_character_str(chan, (char *)data, "", chan->language);
    06254    return res;
    06255 }
    06256
    06257 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
    06258 {
    06259    int res = 0;
    06260
    06261    if (data)
    06262       res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
    06263    return res;
    06264 }
    06265
    06266 int load_pbx(void)
    06267 {
    06268    int x;
    06269
    06270    /* Initialize the PBX */
    06271    if (option_verbose) {
    06272       ast_verbose( "Asterisk PBX Core Initializing\n");
    06273       ast_verbose( "Registering builtin applications:\n");
    06274    }
    06275    AST_LIST_HEAD_INIT_NOLOCK(&globals);
    06276    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
    06277
    06278    /* Register builtin applications */
    06279    for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
    06280       if (option_verbose)
    06281          ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
    06282       if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
    06283          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
    06284          return -1;
    06285       }
    06286    }
    06287    return 0;
    06288 }
    06289
    06290 /*
    06291  * Lock context list functions ...
    06292  */
    06293 int ast_lock_contexts()
    06294 {
    06295    return ast_mutex_lock(&conlock);
    06296 }
    06297
    06298 int ast_unlock_contexts()
    06299 {
    06300    return ast_mutex_unlock(&conlock);
    06301 }
    06302
    06303 /*
    06304  * Lock context ...
    06305  */
    06306 int ast_lock_context(struct ast_context *con)
    06307 {
    06308    return ast_mutex_lock(&con->lock);
    06309 }
    06310
    06311 int ast_unlock_context(struct ast_context *con)
    06312 {
    06313    return ast_mutex_unlock(&con->lock);
    06314 }
    06315
    06316 /*
    06317  * Name functions ...
    06318  */
    06319 const char *ast_get_context_name(struct ast_context *con)
    06320 {
    06321    return con ? con->name : NULL;
    06322 }
    06323
    06324 const char *ast_get_extension_name(struct ast_exten *exten)
    06325 {
    06326    return exten ? exten->exten : NULL;
    06327 }
    06328
    06329 const char *ast_get_extension_label(struct ast_exten *exten)
    06330 {
    06331    return exten ? exten->label : NULL;
    06332 }
    06333
    06334 const char *ast_get_include_name(struct ast_include *inc)
    06335 {
    06336    return inc ? inc->name : NULL;
    06337 }
    06338
    06339 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
    06340 {
    06341    return ip ? ip->pattern : NULL;
    06342 }
    06343
    06344 int ast_get_extension_priority(struct ast_exten *exten)
    06345 {
    06346    return exten ? exten->priority : -1;
    06347 }
    06348
    06349 /*
    06350  * Registrar info functions ...
    06351  */
    06352 const char *ast_get_context_registrar(struct ast_context *c)
    06353 {
    06354    return c ? c->registrar : NULL;
    06355 }
    06356
    06357 const char *ast_get_extension_registrar(struct ast_exten *e)
    06358 {
    06359    return e ? e->registrar : NULL;
    06360 }
    06361
    06362 const char *ast_get_include_registrar(struct ast_include *i)
    06363 {
    06364    return i ? i->registrar : NULL;
    06365 }
    06366
    06367 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
    06368 {
    06369    return ip ? ip->registrar : NULL;
    06370 }
    06371
    06372 int ast_get_extension_matchcid(struct ast_exten *e)
    06373 {
    06374    return e ? e->matchcid : 0;
    06375 }
    06376
    06377 const char *ast_get_extension_cidmatch(struct ast_exten *e)
    06378 {
    06379    return e ? e->cidmatch : NULL;
    06380 }
    06381
    06382 const char *ast_get_extension_app(struct ast_exten *e)
    06383 {
    06384    return e ? e->app : NULL;
    06385 }
    06386
    06387 void *ast_get_extension_app_data(struct ast_exten *e)
    06388 {
    06389    return e ? e->data : NULL;
    06390 }
    06391
    06392 const char *ast_get_switch_name(struct ast_sw *sw)
    06393 {
    06394    return sw ? sw->name : NULL;
    06395 }
    06396
    06397 const char *ast_get_switch_data(struct ast_sw *sw)
    06398 {
    06399    return sw ? sw->data : NULL;
    06400 }
    06401
    06402 const char *ast_get_switch_registrar(struct ast_sw *sw)
    06403 {
    06404    return sw ? sw->registrar : NULL;
    06405 }
    06406
    06407 /*
    06408  * Walking functions ...
    06409  */
    06410 struct ast_context *ast_walk_contexts(struct ast_context *con)
    06411 {
    06412    if (!con)
    06413       return contexts;
    06414    else
    06415       return con->next;
    06416 }
    06417
    06418 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
    06419    struct ast_exten *exten)
    06420 {
    06421    if (!exten)
    06422       return con ? con->root : NULL;
    06423    else
    06424       return exten->next;
    06425 }
    06426
    06427 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
    06428    struct ast_sw *sw)
    06429 {
    06430    if (!sw)
    06431       return con ? con->alts : NULL;
    06432    else
    06433       return sw->next;
    06434 }
    06435
    06436 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
    06437    struct ast_exten *priority)
    06438 {
    06439    if (!priority)
    06440       return exten;
    06441    else
    06442       return priority->peer;
    06443 }
    06444
    06445 struct ast_include *ast_walk_context_includes(struct ast_context *con,
    06446    struct ast_include *inc)
    06447 {
    06448    if (!inc)
    06449       return con ? con->includes : NULL;
    06450    else
    06451       return inc->next;
    06452 }
    06453
    06454 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
    06455    struct ast_ignorepat *ip)
    06456 {
    06457    if (!ip)
    06458       return con ? con->ignorepats : NULL;
    06459    else
    06460       return ip->next;
    06461 }
    06462
    06463 int ast_context_verify_includes(struct ast_context *con)
    06464 {
    06465    struct ast_include *inc;
    06466    int res = 0;
    06467
    06468    for (inc = ast_walk_context_includes(con, NULL); inc; inc = ast_walk_context_includes(con, inc))
    06469       if (!ast_context_find(inc->rname)) {
    06470          res = -1;
    06471          ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
    06472                ast_get_context_name(con), inc->rname);
    06473       }
    06474    return res;
    06475 }
    06476
    06477
    06478 static int __ast_goto_if_exists(struct ast_channel *chan, char *context, char *exten, int priority, int async)
    06479 {
    06480    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
    06481
    06482    if (!chan)
    06483       return -2;
    06484
    06485    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
    06486    if (ast_exists_extension(chan, context ? context : chan->context,
    06487              exten ? exten : chan->exten, priority,
    06488              chan->cid.cid_num))
    06489       return goto_func(chan, context ? context : chan->context,
    06490              exten ? exten : chan->exten, priority);
    06491    else
    06492       return -3;
    06493 }
    06494
    06495 int ast_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
    06496    return __ast_goto_if_exists(chan, context, exten, priority, 0);
    06497 }
    06498
    06499 int ast_async_goto_if_exists(struct ast_channel *chan, char* context, char *exten, int priority) {
    06500    return __ast_goto_if_exists(chan, context, exten, priority, 1);
    06501 }
    06502
    06503 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
    06504 {
    06505    char *s;
    06506    char *exten, *pri, *context;
    06507    char *stringp=NULL;
    06508    int ipri;
    06509    int mode = 0;
    06510
    06511    if (ast_strlen_zero(goto_string)) {
    06512       ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
    06513       return -1;
    06514    }
    06515    s = ast_strdupa(goto_string);
    06516    stringp=s;
    06517    context = strsep(&stringp, "|");
    06518    exten = strsep(&stringp, "|");
    06519    if (!exten) {
    06520       /* Only a priority in this one */
    06521       pri = context;
    06522       exten = NULL;
    06523       context = NULL;
    06524    } else {
    06525       pri = strsep(&stringp, "|");
    06526       if (!pri) {
    06527          /* Only an extension and priority in this one */
    06528          pri = exten;
    06529          exten = context;
    06530          context = NULL;
    06531       }
    06532    }
    06533    if (*pri == '+') {
    06534       mode = 1;
    06535       pri++;
    06536    } else if (*pri == '-') {
    06537       mode = -1;
    06538       pri++;
    06539    }
    06540    if (sscanf(pri, "%30d", &ipri) != 1) {
    06541       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, (exten && strcasecmp(exten, "BYEXTENSION")) ? exten : chan->exten,
    06542          pri, chan->cid.cid_num)) < 1) {
    06543          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
    06544          return -1;
    06545       } else
    06546          mode = 0;
    06547    }
    06548    /* At this point we have a priority and maybe an extension and a context */
    06549
    06550    if (exten && !strcasecmp(exten, "BYEXTENSION"))
    06551       exten = NULL;
    06552
    06553    if (mode)
    06554       ipri = chan->priority + (ipri * mode);
    06555
    06556    ast_explicit_goto(chan, context, exten, ipri);
    06557    ast_cdr_update(chan);
    06558    return 0;
    06559
    06560 }