/*
 * Asterisk -- An open source telephony toolkit.
 *
 * Copyright (C) 1999 - 2006, Digium, Inc.
 *
 * Mark Spencer <markster@digium.com>
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

/*! \file
 * \brief Core PBX routines and definitions.
 */

#ifndef _ASTERISK_PBX_H
#define _ASTERISK_PBX_H

#include "asterisk/channel.h"
#include "asterisk/sched.h"
#include "asterisk/devicestate.h"
#include "asterisk/presencestate.h"
#include "asterisk/chanvars.h"
#include "asterisk/hashtab.h"
#include "asterisk/stringfields.h"
#include "asterisk/xmldoc.h"
#include "asterisk/format.h"

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

#define AST_MAX_APP	32	/*!< Max length of an application */

#define AST_PBX_GOTO_FAILED -3
#define AST_PBX_KEEP    0
#define AST_PBX_REPLACE 1

/*! \brief Special return values from applications to the PBX
 * @{ */
#define AST_PBX_HANGUP                -1    /*!< Jump to the 'h' exten */
#define AST_PBX_OK                     0    /*!< No errors */
#define AST_PBX_ERROR                  1    /*!< Jump to the 'e' exten */
#define AST_PBX_INCOMPLETE             12   /*!< Return to PBX matching, allowing more digits for the extension */
/*! @} */

#define PRIORITY_HINT	-1	/*!< Special Priority for a hint */

/*!
 * \brief Extension states
 * \note States can be combined
 * \ref AstExtState
 */
enum ast_extension_states {
	AST_EXTENSION_REMOVED = -2,	/*!< Extension removed */
	AST_EXTENSION_DEACTIVATED = -1,	/*!< Extension hint removed */
	AST_EXTENSION_NOT_INUSE = 0,	/*!< No device INUSE or BUSY  */
	AST_EXTENSION_INUSE = 1 << 0,	/*!< One or more devices INUSE */
	AST_EXTENSION_BUSY = 1 << 1,	/*!< All devices BUSY */
	AST_EXTENSION_UNAVAILABLE = 1 << 2, /*!< All devices UNAVAILABLE/UNREGISTERED */
	AST_EXTENSION_RINGING = 1 << 3,	/*!< All devices RINGING */
	AST_EXTENSION_ONHOLD = 1 << 4,	/*!< All devices ONHOLD */
};

/*!
 * \brief extension matchcid types
 * \note matchcid in ast_exten retains 0/1, this adds 3rd state for functions to specify all
 * \see ast_context_remove_extension_callerid
 */
enum ast_ext_matchcid_types {
	AST_EXT_MATCHCID_OFF = 0,	/*!< Match only extensions with matchcid=0 */
	AST_EXT_MATCHCID_ON = 1,	/*!< Match only extensions with matchcid=1 AND cidmatch matches */
	AST_EXT_MATCHCID_ANY = 2,	/*!< Match both - used only in functions manipulating ast_exten's */
};

struct ast_context;
struct ast_exten;
struct ast_include;
struct ast_ignorepat;
struct ast_sw;

enum ast_state_cb_update_reason {
	/*! The extension state update is a result of a device state changing on the extension. */
	AST_HINT_UPDATE_DEVICE = 1,
	/*! The extension state update is a result of presence state changing on the extension. */
	AST_HINT_UPDATE_PRESENCE = 2,
};

struct ast_device_state_info {
	enum ast_device_state device_state;
	struct ast_channel *causing_channel;
	char device_name[1];
};

struct ast_state_cb_info {
	enum ast_state_cb_update_reason reason;
	enum ast_extension_states exten_state;
	struct ao2_container *device_state_info; /* holds ast_device_state_info, must be referenced by callback if stored */
	enum ast_presence_state presence_state;
	const char *presence_subtype;
	const char *presence_message;
};

/*! \brief Typedef for devicestate and hint callbacks */
typedef int (*ast_state_cb_type)(const char *context, const char *exten, struct ast_state_cb_info *info, void *data);

/*! \brief Typedef for devicestate and hint callback removal indication callback */
typedef void (*ast_state_cb_destroy_type)(int id, void *data);

/*! \brief Data structure associated with a custom dialplan function */
struct ast_custom_function {
	const char *name;			/*!< Name */
	AST_DECLARE_STRING_FIELDS(
		AST_STRING_FIELD(synopsis);     /*!< Synopsis text for 'show functions' */
		AST_STRING_FIELD(desc);		/*!< Description (help text) for 'show functions &lt;name&gt;' */
		AST_STRING_FIELD(syntax);       /*!< Syntax text for 'core show functions' */
		AST_STRING_FIELD(arguments);    /*!< Arguments description */
		AST_STRING_FIELD(seealso);      /*!< See also */
	);
	enum ast_doc_src docsrc;		/*!< Where the documentation come from */
	/*! Read function, if read is supported */
	ast_acf_read_fn_t read;		/*!< Read function, if read is supported */
	/*! Read function, if read is supported.  Note: only one of read or read2
	 * needs to be implemented.  In new code, read2 should be implemented as
	 * the way forward, but they should return identical results, within the
	 * constraints of buffer size, if both are implemented.  That is, if the
	 * read function is handed a 16-byte buffer, and the result is 17 bytes
	 * long, then the first 15 bytes (remember NULL terminator) should be
	 * the same for both the read and the read2 methods. */
	ast_acf_read2_fn_t read2;
	/*! If no read2 function is provided, what maximum size? */
	size_t read_max;
	/*! Write function, if write is supported */
	ast_acf_write_fn_t write;	/*!< Write function, if write is supported */
	struct ast_module *mod;         /*!< Module this custom function belongs to */
	unsigned int read_escalates:1;  /*!< The read function is to be considered
					 * 'dangerous', and should not be run directly
					 * from external interfaces (AMI, ARI, etc.)
					 * \since 12 */
	unsigned int write_escalates:1; /*!< The write function is to be considered
					 * 'dangerous', and should not be run directly
					 * from external interfaces (AMI, ARI, etc.)
					 * \since 12 */

	AST_RWLIST_ENTRY(ast_custom_function) acflist;
	AST_STRING_FIELD_EXTENDED(since); /*!< Since text for 'show functions' */
	AST_STRING_FIELD_EXTENDED(provided_by);  /*!< Provided-by text for 'show functions' */
};

/*! \brief All switch functions have the same interface, so define a type for them */
typedef int (ast_switch_f)(struct ast_channel *chan, const char *context,
	const char *exten, int priority, const char *callerid, const char *data);

/*!< Data structure associated with an Asterisk switch */
struct ast_switch {
	AST_LIST_ENTRY(ast_switch) list;
	const char *name;			/*!< Name of the switch */
	const char *description;		/*!< Description of the switch */

	ast_switch_f *exists;
	ast_switch_f *canmatch;
	ast_switch_f *exec;
	ast_switch_f *matchmore;
};

struct ast_timing {
	int hastime;                    /*!< If time construct exists */
	unsigned int monthmask;         /*!< Mask for month */
	unsigned int daymask;           /*!< Mask for date */
	unsigned int dowmask;           /*!< Mask for day of week (sun-sat) */
	unsigned int minmask[48];       /*!< Mask for minute */
	char *timezone;                 /*!< NULL, or zoneinfo style timezone */
};

/*!
 * \brief Construct a timing bitmap, for use in time-based conditionals.
 * \param i Pointer to an ast_timing structure.
 * \param info_in Standard string containing a timerange, weekday range, monthday range, and month range, as well as an optional timezone.
 * \retval 1 on success.
 * \retval 0 on failure.
 */
int ast_build_timing(struct ast_timing *i, const char *info_in);

/*!
 * \brief Evaluate a pre-constructed bitmap as to whether the current time falls within the range specified.
 * \param i Pointer to an ast_timing structure.
 * \retval 1 if the time matches.
 * \retval 0 if the current time falls outside of the specified range.
 */
int ast_check_timing(const struct ast_timing *i);

/*!
 * \brief Evaluate a pre-constructed bitmap as to whether a particular time falls within the range specified.
 * \param i Pointer to an ast_timing structure.
 * \param tv Specified time
 * \retval 1 if the time matches.
 * \retval 0 if the time falls outside of the specified range.
 */
int ast_check_timing2(const struct ast_timing *i, const struct timeval tv);

/*!
 * \brief Deallocates memory structures associated with a timing bitmap.
 * \param i Pointer to an ast_timing structure.
 * \retval 0 success
 * \retval non-zero failure (number suitable to pass to \see strerror)
 */
int ast_destroy_timing(struct ast_timing *i);

struct ast_pbx {
	int dtimeoutms;				/*!< Timeout between digits (milliseconds) */
	int rtimeoutms;				/*!< Timeout for response (milliseconds) */
};


/*!
 * \brief Register an alternative dialplan switch
 *
 * \param sw switch to register
 *
 * This function registers a populated ast_switch structure with the
 * asterisk switching architecture.
 *
 * \retval 0 success
 * \retval non-zero failure
 */
int ast_register_switch(struct ast_switch *sw);

/*!
 * \brief Unregister an alternative switch
 *
 * \param sw switch to unregister
 *
 * Unregisters a switch from asterisk.
 */
void ast_unregister_switch(struct ast_switch *sw);

/*!
 * \brief Look up an application
 *
 * \param app name of the app
 *
 * This function searches for the ast_app structure within
 * the apps that are registered for the one with the name
 * you passed in.
 *
 * \return the ast_app structure that matches on success, or NULL on failure
 */
struct ast_app *pbx_findapp(const char *app);

/*!
 * \brief Execute an application
 *
 * \param c channel to execute on
 * \param app which app to execute
 * \param data the data passed into the app
 *
 * This application executes an application on a given channel.  It
 * saves the stack and executes the given application passing in
 * the given data.
 *
 * \retval 0 success
 * \retval -1 failure
 */
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data);

/*!
 * \brief Execute an application
 *
 * \param chan channel to execute on
 * \param app_name name of app to execute
 * \param app_args the data passed into the app
 *
 * This application executes an application by name on a given channel.
 * It is a wrapper around pbx_exec that will perform variable substitution
 * and then execute the application if it exists.
 * If the application is not found, a warning is logged.
 *
 * \retval 0 success
 * \retval -1 failure (including application not found)
 */
int ast_pbx_exec_application(struct ast_channel *chan, const char *app_name, const char *app_args);

/*!
 * \brief Register a new context or find an existing one
 *
 * \param extcontexts pointer to the ast_context structure pointer
 * \param exttable pointer to the hashtable that contains all the elements in extcontexts
 * \param name name of the new context
 * \param registrar registrar of the context
 *
 * This function allows you to play in two environments: the global contexts (active dialplan)
 * or an external context set of your choosing. To act on the external set, make sure extcontexts
 * and exttable are set; for the globals, make sure both extcontexts and exttable are NULL.
 *
 * This will first search for a context with your name.  If it exists already, it will not
 * create a new one.  If it does not exist, it will create a new one with the given name
 * and registrar.
 *
 * \return NULL on failure, and an ast_context structure on success
 */
struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar);

/*!
 * \brief Enable or disable autohints support on a context
 *
 * \param con pointer to the context
 * \param enabled whether autohints are enabled
 *
 */
void ast_context_set_autohints(struct ast_context *con, int enabled);

/*!
 * \brief Merge the temporary contexts into a global contexts list and delete from the
 *        global list the ones that are being added
 *
 * \param extcontexts pointer to the ast_context structure
 * \param exttable pointer to the ast_hashtab structure that contains all the elements in extcontexts
 * \param registrar of the context; if it's set the routine will delete all contexts
 *        that belong to that registrar; if NULL only the contexts that are specified
 *        in extcontexts
 */
void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar);

/*!
 * \brief Destroy a context by name
 *
 * \param context Name of the context to destroy
 * \param registrar who registered it
 *
 * You can optionally leave out the registrar parameter.  It will find it
 * based on the context name.
 *
 * \retval -1 context not found
 * \retval 0 Success
 */
int ast_context_destroy_by_name(const char *context, const char *registrar);

/*!
 * \brief Destroy a context (matches the specified context or ANY context if NULL)
 *
 * \param con context to destroy
 * \param registrar who registered it
 *
 * You can optionally leave out either parameter.  It will find it
 * based on either the ast_context or the registrar name.
 */
void ast_context_destroy(struct ast_context *con, const char *registrar);

/*!
 * \brief Find a context
 *
 * \param name name of the context to find
 *
 * Will search for the context with the given name.
 *
 * \return the ast_context on success, NULL on failure.
 */
struct ast_context *ast_context_find(const char *name);

/*!
 * \brief The result codes when starting the PBX on a channel with ast_pbx_start.
 * \note AST_PBX_CALL_LIMIT refers to the maxcalls call limit in asterisk.conf
 * \see ast_pbx_start
 */
enum ast_pbx_result {
	AST_PBX_SUCCESS = 0,
	AST_PBX_FAILED = -1,
	AST_PBX_CALL_LIMIT = -2,
};

/*!
 * \brief Create a new thread and start the PBX
 *
 * \param c channel to start the pbx on
 *
 * \see ast_pbx_run for a synchronous function to run the PBX in the
 * current thread, as opposed to starting a new one.
 *
 * \retval Zero on success
 * \retval non-zero on failure
 */
enum ast_pbx_result ast_pbx_start(struct ast_channel *c);

/*!
 * \brief Execute the PBX in the current thread
 *
 * \param c channel to run the pbx on
 *
 * This executes the PBX on a given channel. It allocates a new
 * PBX structure for the channel, and provides all PBX functionality.
 * See ast_pbx_start for an asynchronous function to run the PBX in a
 * new thread as opposed to the current one.
 *
 * \retval Zero on success
 * \retval non-zero on failure
 */
enum ast_pbx_result ast_pbx_run(struct ast_channel *c);

/*!
 * \brief Options for ast_pbx_run()
 */
struct ast_pbx_args {
	union {
		/*! Pad this out so that we have plenty of room to add options
		 *  but still maintain ABI compatibility over time. */
		uint64_t __padding;
		struct {
			/*! Do not hangup the channel when the PBX is complete. */
			unsigned int no_hangup_chan:1;
		};
	};
};

/*!
 * \brief Execute the PBX in the current thread
 *
 * \param c channel to run the pbx on
 * \param args options for the pbx
 *
 * This executes the PBX on a given channel. It allocates a new
 * PBX structure for the channel, and provides all PBX functionality.
 * See ast_pbx_start for an asynchronous function to run the PBX in a
 * new thread as opposed to the current one.
 *
 * \retval Zero on success
 * \retval non-zero on failure
 */
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args);

/*!
 * \brief Run the h exten from the given context.
 * \since 11.0
 *
 * \param chan Channel to run the h exten on.
 * \param context Context the h exten is in.
 */
void ast_pbx_h_exten_run(struct ast_channel *chan, const char *context);

/*!
 * \brief Run all hangup handlers on the channel.
 * \since 11.0
 *
 * \param chan Channel to run the hangup handlers on.
 *
 * \note Absolutely _NO_ channel locks should be held before calling this function.
 *
 * \retval Zero if no hangup handlers run.
 * \retval non-zero if hangup handlers were run.
 */
int ast_pbx_hangup_handler_run(struct ast_channel *chan);

/*!
 * \brief Init the hangup handler container on a channel.
 * \since 11.0
 *
 * \param chan Channel to init the hangup handler container on.
 */
void ast_pbx_hangup_handler_init(struct ast_channel *chan);

/*!
 * \brief Destroy the hangup handler container on a channel.
 * \since 11.0
 *
 * \param chan Channel to destroy the hangup handler container on.
 */
void ast_pbx_hangup_handler_destroy(struct ast_channel *chan);

/*!
 * \brief Pop the top of the channel hangup handler stack.
 * \since 11.0
 *
 * \param chan Channel to push the hangup handler onto.
 *
 * \retval TRUE if a handler was popped off of the stack.
 */
int ast_pbx_hangup_handler_pop(struct ast_channel *chan);

/*!
 * \brief Push the given hangup handler onto the channel hangup handler stack.
 * \since 11.0
 *
 * \param chan Channel to push the hangup handler onto.
 * \param handler Gosub application parameter string.
 */
void ast_pbx_hangup_handler_push(struct ast_channel *chan, const char *handler);

/*!
 * \brief Add and extension to an extension context.
 *
 * \param context context to add the extension to
 * \param replace
 * \param extension extension to add
 * \param priority priority level of extension addition
 * \param label extension label
 * \param callerid pattern to match CallerID, or NULL to match any CallerID
 * \param application application to run on the extension with that priority level
 * \param data data to pass to the application
 * \param datad a pointer to a function that will deallocate \c data when needed
 *              or NULL if \c data does not need to be freed.
 * \param registrar who registered the extension
 *
 * \note On any failure, the function pointed to by \c datap will be called and passed the
 *       \c data pointer.
 *
 * \retval 0 success
 * \retval -1 failure
 */
int ast_add_extension(const char *context, int replace, const char *extension,
	int priority, const char *label, const char *callerid,
	const char *application, void *data, void (*datad)(void *), const char *registrar);

/*!
 * \brief Add an extension to an extension context, this time with an ast_context *.
 *
 * \param con context to add the extension to
 * \param replace
 * \param extension extension to add
 * \param priority priority level of extension addition
 * \param label extension label
 * \param callerid pattern to match CallerID, or NULL to match any CallerID
 * \param application application to run on the extension with that priority level
 * \param data data to pass to the application
 * \param datad a pointer to a function that will deallocate \c data when needed
 *              or NULL if \c data does not need to be freed.
 * \param registrar who registered the extension
 * \param registrar_file optional configuration file that defines this extension
 * \param registrar_line optional line number of configuration file that defines extension
 *
 * \note On any failure, the function pointed to by \c datap will be called and passed the
 *       \c data pointer.
 *
 * \retval 0 success
 * \retval -1 failure
 */
int ast_add_extension2(struct ast_context *con, int replace, const char *extension,
	int priority, const char *label, const char *callerid,
	const char *application, void *data, void (*datad)(void *), const char *registrar,
	const char *registrar_file, int registrar_line);

/*!
 * \brief Same as ast_add_extension2, but assumes you have already locked context
 * \since 12.0.0
 *
 * \note con must be write locked prior to calling. For details about the arguments,
 *       check ast_add_extension()
 */
int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension,
	int priority, const char *label, const char *callerid,
	const char *application, void *data, void (*datad)(void *), const char *registrar,
	const char *registrar_file, int registrar_line);

/*!
 * \brief Map devstate to an extension state.
 *
 * \param[in] devstate device state
 *
 * \return the extension state mapping.
 */
enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate);

/*!
 * \brief Uses hint and devicestate callback to get the state of an extension
 *
 * \param c this is not important
 * \param context which context to look in
 * \param exten which extension to get state
 *
 * \return extension state as defined in the ast_extension_states enum
 */
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten);

/*!
 * \brief Uses hint and devicestate callback to get the extended state of an extension
 * \since 11
 *
 * \param c this is not important
 * \param context which context to look in
 * \param exten which extension to get state
 * \param[out] device_state_info ptr to an ao2_container with extended state info, must be unref'd after use.
 *
 * \return extension state as defined in the ast_extension_states enum
 */
int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten,
	struct ao2_container **device_state_info);

/*!
 * \brief Uses hint and presence state callback to get the presence state of an extension
 *
 * \param c this is not important
 * \param context which context to look in
 * \param exten which extension to get state
 * \param[out] subtype Further information regarding the presence returned
 * \param[out] message Custom message further describing current presence
 *
 * \note The subtype and message are dynamically allocated and must be freed by
 * the caller of this function.
 *
 * \return returns the presence state value.
 */
int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message);

/*!
 * \brief Return string representation of the state of an extension
 *
 * \param extension_state is the numerical state delivered by ast_extension_state
 *
 * \return the state of an extension as string
 */
const char *ast_extension_state2str(int extension_state);

/*!
 * \brief Add watcher for extension states with destructor.
 * \since 1.8.9
 * \since 10.1.0
 *
 * \param context which context to look in
 * \param exten which extension to get state
 * \param change_cb callback to call if state changed
 * \param destroy_cb callback to call when the watcher is destroyed.
 * \param data to pass to callbacks
 *
 * \note If context and exten are NULL then the added watcher is global.
 * The change_cb is called for every extension's state change.
 *
 * \note The change_cb is called if the state of an extension is changed.
 *
 * \note The destroy_cb is called when the watcher is deleted so the
 * watcher can release any associated resources.
 *
 * \retval -1 on failure
 * \retval 0 Global watcher added successfully
 * \retval ID on success
 */
int ast_extension_state_add_destroy(const char *context, const char *exten,
	ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data);

/*!
 * \brief Add watcher for extended extension states with destructor.
 * \since 11
 *
 * \param context which context to look in
 * \param exten which extension to get state
 * \param change_cb callback to call if state changed
 * \param destroy_cb callback to call when the watcher is destroyed.
 * \param data to pass to callbacks
 *
 * \note If context and exten are NULL then the added watcher is global.
 * The change_cb is called for every extension's state change.
 *
 * \note The change_cb is called if the state of an extension is changed.
 * The extended state is passed to the callback in the device_state_info
 * member of ast_state_cb_info.
 *
 * \note The destroy_cb is called when the watcher is deleted so the
 * watcher can release any associated resources.
 *
 * \retval -1 on failure
 * \retval 0 Global watcher added successfully
 * \retval ID on success
 */
int ast_extension_state_add_destroy_extended(const char *context, const char *exten,
	ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data);

/*!
 * \brief Add watcher for extension states.
 *
 * \param context which context to look in
 * \param exten which extension to get state
 * \param change_cb callback to call if state changed
 * \param data to pass to callback
 *
 * \note If context and exten are NULL then the added watcher is global.
 * The change_cb is called for every extension's state change.
 *
 * \note The change_cb is called if the state of an extension is changed.
 *
 * \retval -1 on failure
 * \retval 0 Global watcher added successfully
 * \retval ID on success
 */
int ast_extension_state_add(const char *context, const char *exten,
	ast_state_cb_type change_cb, void *data);

/*!
 * \brief Add watcher for extended extension states.
 * \since 11
 *
 * \param context which context to look in
 * \param exten which extension to get state
 * \param change_cb callback to call if state changed
 * \param data to pass to callback
 *
 * \note If context and exten are NULL then the added watcher is global.
 * The change_cb is called for every extension's state change.
 *
 * \note The change_cb is called if the state of an extension is changed.
 * The extended state is passed to the callback in the device_state_info
 * member of ast_state_cb_info.
 *
 * \retval -1 on failure
 * \retval 0 Global watcher added successfully
 * \retval ID on success
 */
int ast_extension_state_add_extended(const char *context, const char *exten,
	ast_state_cb_type change_cb, void *data);

/*!
 * \brief Deletes a state change watcher by ID
 *
 * \param id of the state watcher to delete (0 for global watcher)
 * \param change_cb callback to call if state changed (Used if id == 0 (global))
 *
 * \retval 0 success
 * \retval -1 failure
 */
int ast_extension_state_del(int id, ast_state_cb_type change_cb);

/*!
 * \brief If an extension hint exists, return non-zero
 *
 * \param hint buffer for hint
 * \param hintsize size of hint buffer, in bytes
 * \param name buffer for name portion of hint
 * \param namesize size of name buffer
 * \param c Channel from which to return the hint.  This is only important when the hint or name contains an expression to be expanded.
 * \param context which context to look in
 * \param exten which extension to search for
 *
 * \return If an extension within the given context with the priority PRIORITY_HINT
 * is found, a non zero value will be returned.
 * Otherwise, 0 is returned.
 */
int ast_get_hint(char *hint, int hintsize, char *name, int namesize,
	struct ast_channel *c, const char *context, const char *exten);

/*!
 * \brief If an extension hint exists, return non-zero
 *
 * \param hint buffer for hint
 * \param hintsize Maximum size of hint buffer (<0 to prevent growth, >0 to limit growth to that number of bytes, or 0 for unlimited growth)
 * \param name buffer for name portion of hint
 * \param namesize Maximum size of name buffer (<0 to prevent growth, >0 to limit growth to that number of bytes, or 0 for unlimited growth)
 * \param c Channel from which to return the hint.  This is only important when the hint or name contains an expression to be expanded.
 * \param context which context to look in
 * \param exten which extension to search for
 *
 * \return If an extension within the given context with the priority PRIORITY_HINT
 * is found, a non zero value will be returned.
 * Otherwise, 0 is returned.
 */
int ast_str_get_hint(struct ast_str **hint, ssize_t hintsize, struct ast_str **name, ssize_t namesize,
	struct ast_channel *c, const char *context, const char *exten);

/*!
 * \brief Determine whether an extension exists
 *
 * \param c this is not important
 * \param context which context to look in
 * \param exten which extension to search for
 * \param priority priority of the action within the extension
 * \param callerid callerid to search for
 *
 * \note It is possible for autoservice to be started and stopped on c during this
 * function call, it is important that c is not locked prior to calling this. Otherwise
 * a deadlock may occur
 *
 * \return If an extension within the given context(or callerid) with the given priority
 *         is found a non zero value will be returned. Otherwise, 0 is returned.
 */
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten,
	int priority, const char *callerid);

/*!
 * \brief Find the priority of an extension that has the specified label
 *
 * \param c this is not important
 * \param context which context to look in
 * \param exten which extension to search for
 * \param label label of the action within the extension to match to priority
 * \param callerid callerid to search for
 *
 * \note It is possible for autoservice to be started and stopped on c during this
 * function call, it is important that c is not locked prior to calling this. Otherwise
 * a deadlock may occur
 *
 * \retval the priority which matches the given label in the extension
 * \retval -1 if not found.
 */
int ast_findlabel_extension(struct ast_channel *c, const char *context,
	const char *exten, const char *label, const char *callerid);

/*!
 * \brief Find the priority of an extension that has the specified label
 *
 * \note It is possible for autoservice to be started and stopped on c during this
 * function call, it is important that c is not locked prior to calling this. Otherwise
 * a deadlock may occur
 *
 * \note This function is the same as ast_findlabel_extension, except that it accepts
 * a pointer to an ast_context structure to specify the context instead of the
 * name of the context. Otherwise, the functions behave the same.
 */
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con,
	const char *exten, const char *label, const char *callerid);

/*!
 * \brief Looks for a valid matching extension
 *
 * \param c not really important
 * \param context context to search within
 * \param exten extension to check
 * \param priority priority of extension path
 * \param callerid callerid of extension being searched for
 *
 * \note It is possible for autoservice to be started and stopped on c during this
 * function call, it is important that c is not locked prior to calling this. Otherwise
 * a deadlock may occur
 *
 * \return If "exten" *could be* a valid extension in this context with or without
 * some more digits, return non-zero.  Basically, when this returns 0, no matter
 * what you add to exten, it's not going to be a valid extension anymore
 */
int ast_canmatch_extension(struct ast_channel *c, const char *context,
	const char *exten, int priority, const char *callerid);

/*!
 * \brief Looks to see if adding anything to this extension might match something. (exists ^ canmatch)
 *
 * \param c not really important XXX
 * \param context context to search within
 * \param exten extension to check
 * \param priority priority of extension path
 * \param callerid callerid of extension being searched for
 *
 * \note It is possible for autoservice to be started and stopped on c during this
 * function call, it is important that c is not locked prior to calling this. Otherwise
 * a deadlock may occur
 *
 * \return If "exten" *could match* a valid extension in this context with
 * some more digits, return non-zero.  Does NOT return non-zero if this is
 * an exact-match only.  Basically, when this returns 0, no matter
 * what you add to exten, it's not going to be a valid extension anymore
 */
int ast_matchmore_extension(struct ast_channel *c, const char *context,
	const char *exten, int priority, const char *callerid);

/*!
 * \brief Determine if a given extension matches a given pattern (in NXX format)
 *
 * \param pattern pattern to match
 * \param extension extension to check against the pattern.
 *
 * Checks whether or not the given extension matches the given pattern.
 *
 * \retval 1 on match
 * \retval 0 on failure
 */
int ast_extension_match(const char *pattern, const char *extension);

int ast_extension_close(const char *pattern, const char *data, int needmore);

/*!
 * \brief Determine if one extension should match before another
 *
 * \param a extension to compare with b
 * \param b extension to compare with a
 *
 * Checks whether or extension a should match before extension b
 *
 * \retval 0 if the two extensions have equal matching priority
 * \retval 1 on a > b
 * \retval -1 on a < b
 */
int ast_extension_cmp(const char *a, const char *b);

/*!
 * \brief Launch a new extension (i.e. new stack)
 *
 * \param c not important
 * \param context which context to generate the extension within
 * \param exten new extension to add
 * \param priority priority of new extension
 * \param callerid callerid of extension
 * \param found
 * \param combined_find_spawn
 *
 * This adds a new extension to the asterisk extension list.
 *
 * \note It is possible for autoservice to be started and stopped on c during this
 * function call, it is important that c is not locked prior to calling this. Otherwise
 * a deadlock may occur
 *
 * \retval 0 on success
 * \retval -1 on failure.
 */
int ast_spawn_extension(struct ast_channel *c, const char *context,
      const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn);

/*!
 * \brief Add a context include
 *
 * \param context context to add include to
 * \param include new include to add
 * \param registrar who's registering it
 *
 * Adds an include taking a char * string as the context parameter
 *
 * \retval 0 on success
 * \retval -1 on error
*/
int ast_context_add_include(const char *context, const char *include,
	const char *registrar);

/*!
 * \brief Add a context include
 *
 * Adds an include taking a struct ast_context as the first parameter
 *
 * \note See ast_context_add_include for information on arguments
 */
int ast_context_add_include2(struct ast_context *con, const char *value,
	const char *registrar);

/*!
 * \brief Remove a context include
 *
 * \note See ast_context_add_include for information on arguments
 */
int ast_context_remove_include(const char *context, const char *include,
	const char *registrar);

/*!
 * \brief Removes an include by an ast_context structure
 *
 * \note See ast_context_add_include for information on arguments
 */
int ast_context_remove_include2(struct ast_context *con, const char *include,
	const char *registrar);

/*!
 * \brief Verifies includes in an ast_contect structure
 *
 * \param con context in which to verify the includes
 *
 * \retval 0 if no problems found
 * \retval -1 if there were any missing context
 */
int ast_context_verify_includes(struct ast_context *con);

/*!
 * \brief Add a switch
 *
 * \param context context to which to add the switch
 * \param sw switch to add
 * \param data data to pass to switch
 * \param eval whether to evaluate variables when running switch
 * \param registrar whoever registered the switch
 *
 * This function registers a switch with the asterisk switch architecture
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_context_add_switch(const char *context, const char *sw, const char *data,
	int eval, const char *registrar);

/*!
 * \brief Adds a switch (first param is a ast_context)
 *
 * \note See ast_context_add_switch() for argument information, with the exception of
 *       the first argument. In this case, it's a pointer to an ast_context structure
 *       as opposed to the name.
 */
int ast_context_add_switch2(struct ast_context *con, const char *sw, const char *data,
	int eval, const char *registrar);

/*!
 * \brief Remove a switch
 *
 * Removes a switch with the given parameters
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_context_remove_switch(const char *context, const char *sw,
	const char *data, const char *registrar);

int ast_context_remove_switch2(struct ast_context *con, const char *sw,
	const char *data, const char *registrar);

/*!
 * \brief Simply remove extension from context
 *
 * \param context context to remove extension from
 * \param extension which extension to remove
 * \param priority priority of extension to remove (0 to remove all)
 * \param registrar registrar of the extension
 *
 * This function removes an extension from a given context.
 *
 * \retval 0 on success
 * \retval -1 on failure
 *
 * @{
 */
int ast_context_remove_extension(const char *context, const char *extension, int priority,
	const char *registrar);

int ast_context_remove_extension2(struct ast_context *con, const char *extension,
	int priority, const char *registrar, int already_locked);

int ast_context_remove_extension_callerid(const char *context, const char *extension,
	int priority, const char *callerid, int matchcid, const char *registrar);

int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension,
	int priority, const char *callerid, int matchcid, const char *registrar,
	int already_locked);
/*! @} */

/*!
 * \brief Add an ignorepat
 *
 * \param context which context to add the ignorepattern to
 * \param ignorepat ignorepattern to set up for the extension
 * \param registrar registrar of the ignore pattern
 *
 * Adds an ignore pattern to a particular context.
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_context_add_ignorepat(const char *context, const char *ignorepat, const char *registrar);

int ast_context_add_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar);

/*!
 * \brief Remove an ignorepat
 *
 * \param context context from which to remove the pattern
 * \param ignorepat the pattern to remove
 * \param registrar the registrar of the ignore pattern
 *
 * This removes the given ignorepattern
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar);

int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar);

/*!
 * \brief Checks to see if a number should be ignored
 *
 * \param context context to search within
 * \param pattern to check whether it should be ignored or not
 *
 * Check if a number should be ignored with respect to dialtone cancellation.
 *
 * \retval 0 if the pattern should not be ignored
 * \retval non-zero if the pattern should be ignored
 */
int ast_ignore_pattern(const char *context, const char *pattern);

/* Locking functions for outer modules, especially for completion functions */

/*!
 * \brief Write locks the context list
 *
 * \retval 0 on success
 * \retval -1 on error
 */
int ast_wrlock_contexts(void);

/*!
 * \brief Read locks the context list
 *
 * \retval 0 on success
 * \retval -1 on error
 */
int ast_rdlock_contexts(void);

/*!
 * \brief Unlocks contexts
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_unlock_contexts(void);

/*!
 * \brief Write locks a given context
 *
 * \param con context to lock
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_wrlock_context(struct ast_context *con);

/*!
 * \brief Read locks a given context
 *
 * \param con context to lock
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_rdlock_context(struct ast_context *con);

/*!
 * \retval Unlocks the given context
 *
 * \param con context to unlock
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_unlock_context(struct ast_context *con);

/*!
 * \brief Set the channel to next execute the specified dialplan location.
 * \see ast_async_parseable_goto, ast_async_goto_if_exists
 *
 * \note If the AST_SOFTHANGUP_ASYNCGOTO flag is set,
 * it can prevent the dialplan location from being overwritten by ast_explicit_goto.
 * \note Do _NOT_ hold any channel locks when calling this function.
 */
int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority);

/*!
 * \brief Set the channel to next execute the specified dialplan location.
 */
int ast_async_goto_by_name(const char *chan, const char *context, const char *exten, int priority);

enum ast_pbx_outgoing_sync {
	AST_OUTGOING_NO_WAIT = 0,       /*!< Don't wait for originated call to answer */
	AST_OUTGOING_WAIT = 1,          /*!< Wait for originated call to answer */
	AST_OUTGOING_WAIT_COMPLETE = 2, /*!< Wait for originated call to answer and hangup */
};

/*!
 * \brief Synchronously or asynchronously make an outbound call and send it to a
 * particular extension
 *
 * \param type The channel technology to create
 * \param cap The format capabilities for the channel
 * \param addr Address data to pass to the channel technology driver
 * \param timeout How long we should attempt to dial the outbound channel
 * \param context The destination context for the outbound channel
 * \param exten The destination extension for the outbound channel
 * \param priority The destination priority for the outbound channel
 * \param reason Optional.  If provided, the dialed status of the outgoing channel.
 *        Codes are AST_CONTROL_xxx values.  Valid only if synchronous is non-zero.
 * \param synchronous defined by the ast_pbx_outgoing_sync enum.
 *        If \c AST_OUTGOING_NO_WAIT then don't wait for anything.
 *        If \c AST_OUTGOING_WAIT then block until the outbound channel answers or
 *        the call fails.
 *        If \c AST_OUTGOING_WAIT_COMPLETE then wait for the call to complete or
 *        fail.
 *        If \c AST_OUTGOING_WAIT or \c AST_OUTGOING_WAIT_COMPLETE is specified,
 *        the call doesn't answer, and \c failed\@context exists then run a channel
 *        named \c OutgoingSpoolFailed at \c failed\@context.
 * \param cid_num The caller ID number to set on the outbound channel
 * \param cid_name The caller ID name to set on the outbound channel
 * \param vars Variables to set on the outbound channel
 * \param account The accountcode for the outbound channel
 * \param locked_channel Optional.  The outbound channel that was created if success
 *        is returned.  Otherwise it is set to NULL.  This is returned both locked
 *        and reference bumped.
 * \param early_media If non-zero the channel "answers" when progress is indicated.
 * \param assignedids Optional. The uniqueid(s) to assign the channel(s) that are created.
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const char *addr,
	int timeout, const char *context, const char *exten, int priority, int *reason,
	int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
	const char *account, struct ast_channel **locked_channel, int early_media,
	const struct ast_assigned_ids *assignedids);

int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr,
	int timeout, const char *context, const char *exten, int priority, int *reason,
	int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
	const char *account, struct ast_channel **locked_channel, int early_media,
	const struct ast_assigned_ids *assignedids, const char *predial_callee);

/*!
 * \brief Synchronously or asynchronously make an outbound call and execute an
 *  application on the channel.
 *
 * Note that when the application stops executing, the channel is hungup.
 *
 * \param type The channel technology to create
 * \param cap The format capabilities for the channel
 * \param addr Address data to pass to the channel technology driver
 * \param timeout How long we should attempt to dial the outbound channel
 * \param app The name of the application to execute
 * \param appdata Data to pass to the application
 * \param reason Optional.  If provided, the dialed status of the outgoing channel.
 *        Codes are AST_CONTROL_xxx values.  Valid only if synchronous is non-zero.
 * \param synchronous defined by the ast_pbx_outgoing_sync enum.
 *        If \c AST_OUTGOING_NO_WAIT then don't wait for anything.
 *        If \c AST_OUTGOING_WAIT then block until the outbound channel answers or
 *        the call fails.
 *        If \c AST_OUTGOING_WAIT_COMPLETE then wait for the call to complete or
 *        fail.
 * \param cid_num The caller ID number to set on the outbound channel
 * \param cid_name The caller ID name to set on the outbound channel
 * \param vars Variables to set on the outbound channel
 * \param account The accountcode for the outbound channel
 * \param locked_channel Optional.  The outbound channel that was created if success
 *        is returned.  Otherwise it is set to NULL.  This is returned both locked
 *        and reference bumped.
 * \param assignedids Optional. The uniqueid(s) to assign the channel(s) that are created.
 *
 * \retval 0 on success
 * \retval -1 on failure
 */
int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const char *addr,
	int timeout, const char *app, const char *appdata, int *reason, int synchronous,
	const char *cid_num, const char *cid_name, struct ast_variable *vars,
	const char *account, struct ast_channel **locked_channel,
	const struct ast_assigned_ids *assignedids);

int ast_pbx_outgoing_app_predial(const char *type, struct ast_format_cap *cap, const char *addr,
	int timeout, const char *app, const char *appdata, int *reason, int synchronous,
	const char *cid_num, const char *cid_name, struct ast_variable *vars,
	const char *account, struct ast_channel **locked_channel,
	const struct ast_assigned_ids *assignedids, const char *predial_callee);

/*!
 * \brief Evaluate a condition
 *
 * \retval 0 if the condition is NULL or of zero length
 * \retval int If the string is an integer, the integer representation of
 *             the integer is returned
 * \retval 1 Any other non-empty string
 */
int pbx_checkcondition(const char *condition);

/*! @name
 * Functions for returning values from structures */
/*! @{ */
const char *ast_get_context_name(struct ast_context *con);
const char *ast_get_extension_name(struct ast_exten *exten);
struct ast_context *ast_get_extension_context(struct ast_exten *exten);
const char *ast_get_include_name(const struct ast_include *include);
const char *ast_get_ignorepat_name(const struct ast_ignorepat *ip);
const char *ast_get_switch_name(const struct ast_sw *sw);
const char *ast_get_switch_data(const struct ast_sw *sw);
int ast_get_switch_eval(const struct ast_sw *sw);

/*! @} */

/*! @name Other Extension stuff */
/*! @{ */
int ast_get_extension_priority(struct ast_exten *exten);
int ast_get_extension_matchcid(struct ast_exten *e);
const char *ast_get_extension_cidmatch(struct ast_exten *e);
const char *ast_get_extension_app(struct ast_exten *e);
const char *ast_get_extension_label(struct ast_exten *e);
void *ast_get_extension_app_data(struct ast_exten *e);

/*!
 * \brief Fill a string buffer with the data at a dialplan extension
 *
 * \param buf String buffer
 * \param bufsize Size of buf
 * \param c Channel
 * \param context Dialplan context
 * \param exten Dialplan extension
 * \param priority Dialplan priority
 *
 * \retval -1 Failed to obtain extension data
 * \retval 0 Successfully obtained extension data
 */
int ast_get_extension_data(char *buf, int bufsize, struct ast_channel *c,
	const char *context, const char *exten, int priority);
/*! @} */

/*! @name Registrar info functions ... */
/*! @{ */
const char *ast_get_context_registrar(struct ast_context *c);
const char *ast_get_extension_registrar(struct ast_exten *e);
const char *ast_get_include_registrar(const struct ast_include *i);
const char *ast_get_ignorepat_registrar(const struct ast_ignorepat *ip);
const char *ast_get_switch_registrar(const struct ast_sw *sw);
/*! @} */

/*!
 * \brief Get name of configuration file used by registrar to register this extension
 *
 * \retval NULL if registrar did not indicate config file when registering the extension
 * \retval name of the file used to register the extension
 */
const char *ast_get_extension_registrar_file(struct ast_exten *e);

/*!
 * \brief Get line number of configuration file used by registrar to register this extension
 *
 * \retval 0 if the line wasn't indicated when the extension was registered
 * \retval positive integer indicating what line in the config file was responsible for
 *         registering the extension.
 */
int ast_get_extension_registrar_line(struct ast_exten *e);

/*! @name Walking functions ... */
/*! @{ */
struct ast_context *ast_walk_contexts(struct ast_context *con);
struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
	struct ast_exten *priority);
struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
	struct ast_exten *priority);
const struct ast_include *ast_walk_context_includes(const struct ast_context *con,
	const struct ast_include *inc);
const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con,
	const struct ast_ignorepat *ip);
const struct ast_sw *ast_walk_context_switches(const struct ast_context *con,
	const struct ast_sw *sw);
/*! @} */

/*! @name Iterator functions ... */
/*! @{ */
int ast_context_includes_count(const struct ast_context *con);
const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx);
int ast_context_ignorepats_count(const struct ast_context *con);
const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx);
int ast_context_switches_count(const struct ast_context *con);
const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx);
/*! @} */

/*!
 * \brief Create a human-readable string, specifying all variables and their corresponding values.
 * \param chan Channel from which to read variables
 * \param buf Dynamic string in which to place the result (should be allocated with ast_str_create).
 * \see ast_str_create
 * \note Will lock the channel.
 */
int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf);

/*!
 * \brief Return a pointer to the value of the corresponding channel variable.
 * \note Will lock the channel.
 *
 * \note This function will return a pointer to the buffer inside the channel
 * variable.  This value should only be accessed with the channel locked.  If
 * the value needs to be kept around, it should be done by using the following
 * thread-safe code:
 * \code
 *		const char *var;
 *
 *		ast_channel_lock(chan);
 *		if ((var = pbx_builtin_getvar_helper(chan, "MYVAR"))) {
 *			var = ast_strdupa(var);
 *		}
 *		ast_channel_unlock(chan);
 * \endcode
 */
const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name);

/*!
 * \brief Add a variable to the channel variable stack, without removing any previously set value.
 * \note Will lock the channel.
 */
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value);

/*!
 * \brief Add a variable to the channel variable stack, removing the most recently set value for the same name.
 * \note Will lock the channel.  May also be used to set a channel dialplan function to a particular value.
 * \see ast_func_write
 * \return -1 if the dialplan function fails to be set
 * \version 1.8 changed the function to return an error code
 */
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value);

/*!
 * \brief Retrieve the value of a builtin variable or variable from the channel variable stack.
 * \note Will lock the channel.
 */
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp);
void pbx_builtin_clear_globals(void);

/*!
 * \brief Parse and set a single channel variable, where the name and value are separated with an '=' character.
 * \note Will lock the channel.
 */
int pbx_builtin_setvar(struct ast_channel *chan, const char *data);

/*!
 * \brief Parse and set multiple channel variables, where the pairs are separated by the ',' character, and name and value are separated with an '=' character.
 * \note Will lock the channel.
 */
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data);

int pbx_builtin_raise_exception(struct ast_channel *chan, const char *data);

/*! @name Substitution routines, using static string buffers
 * @{ */
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count);
void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count);
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used);

/*!
 * \brief Substitutes variables, similar to pbx_substitute_variables_helper_full, but allows passing the context, extension, and priority in.
 */
void pbx_substitute_variables_helper_full_location(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int cp2_size, size_t *used, const char *context, const char *exten, int pri);
/*! @} */

/*! @name Substitution routines, using dynamic string buffers
 * @{ */

/*!
 * \param buf Result will be placed in this buffer.
 * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
 * \param chan Channel variables from which to extract values, and channel to pass to any dialplan functions.
 * \param headp If no channel is specified, a channel list from which to extract variable values
 * \param var Variable name to retrieve.
 */
const char *ast_str_retrieve_variable(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, struct varshead *headp, const char *var);

/*!
 * \param buf Result will be placed in this buffer.
 * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
 * \param chan Channel variables from which to extract values, and channel to pass to any dialplan functions.
 * \param templ Variable template to expand.
 */
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ);

/*!
 * \param buf Result will be placed in this buffer.
 * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
 * \param headp If no channel is specified, a channel list from which to extract variable values
 * \param templ Variable template to expand.
 */
void ast_str_substitute_variables_varshead(struct ast_str **buf, ssize_t maxlen, struct varshead *headp, const char *templ);

/*!
 * \param buf Result will be placed in this buffer.
 * \param maxlen -1 if the buffer should not grow, 0 if the buffer may grow to any size, and >0 if the buffer should grow only to that number of bytes.
 * \param c Channel variables from which to extract values, and channel to pass to any dialplan functions.
 * \param headp If no channel is specified, a channel list from which to extract variable values
 * \param templ Variable template to expand.
 * \param used Number of bytes read from the template.  (May be NULL)
 */
void ast_str_substitute_variables_full(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used);

/*!
 * \brief Perform variable/function/expression substitution on an ast_str
 *
 * \param buf      Result will be placed in this buffer.
 * \param maxlen   -1 if the buffer should not grow, 0 if the buffer
 *                 may grow to any size, and >0 if the buffer should
 *                 grow only to that number of bytes.
 * \param c        A channel from which to extract values, and to pass
 *                 to any dialplan functions.
 * \param headp    A channel variables list to also search for variables.
 * \param templ    Variable template to expand.
 * \param used     Number of bytes read from the template.  (May be NULL)
 * \param use_both Normally, if a channel is specified, headp is ignored.
 *                 If this parameter is set to 1 and both a channel and headp
 *                 are specified, the channel will be searched for variables
 *                 first and any not found will be searched for in headp.
 */
void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen,
	struct ast_channel *c, struct varshead *headp, const char *templ,
	size_t *used, int use_both);

/*! @} */

int ast_extension_patmatch(const char *pattern, const char *data);

/*! Set "autofallthrough" flag, if newval is <0, does not actually set.  If
  set to 1, sets to auto fall through.  If newval set to 0, sets to no auto
  fall through (reads extension instead).  Returns previous value. */
int pbx_set_autofallthrough(int newval);

/*! Set "extenpatternmatchnew" flag, if newval is <0, does not actually set.  If
  set to 1, sets to use the new Trie-based pattern matcher.  If newval set to 0, sets to use
  the old linear-search algorithm.  Returns previous value. */
int pbx_set_extenpatternmatchnew(int newval);

/*! Set "overrideswitch" field.  If set and of nonzero length, all contexts
 * will be tried directly through the named switch prior to any other
 * matching within that context.
 * \since 1.6.1
 */
void pbx_set_overrideswitch(const char *newval);

/*!
 * \note This function will handle locking the channel as needed.
 */
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority);

/*!
 * \note This function will handle locking the channel as needed.
 */
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string);

/*!
 * \note This function will handle locking the channel as needed.
 */
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string);

/*!
 * \note This function will handle locking the channel as needed.
 * \note If the AST_SOFTHANGUP_ASYNCGOTO flag is set on the channel, this function will fail and return -1.
 */
int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority);

/*!
 * \note This function will handle locking the channel as needed.
 */
int ast_async_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority);

/*!
 * \brief Parses a dialplan location into context, extension, priority
 *
 * \param chan Channel to execute on
 * \param context Pointer to initial value for context.
 * \param exten Pointer to initial value for exten.
 * \param pri Pointer to initial value for pri
 * \param ipri Pointer to integer value of priority
 * \param mode Pointer to mode (or NULL if mode is not used)
 * \param rest Pointer to buffer to capture rest of parsing (or NULL if not used)
 *
 * strsep should be used to initially populate context, exten, and pri prior
 * to calling this function. All arguments are modified in place.
 *
 * \retval 0 success
 * \retval non-zero failure
 */
int pbx_parse_location(struct ast_channel *chan, char **context, char **exten, char **pri, int *ipri, int *mode, char *rest);

struct ast_custom_function* ast_custom_function_find(const char *name);

/*!
 * \brief Unregister a custom function
 */
int ast_custom_function_unregister(struct ast_custom_function *acf);

/*!
 * \brief Description of the ways in which a function may escalate privileges.
 */
enum ast_custom_function_escalation {
	AST_CFE_NONE,
	AST_CFE_READ,
	AST_CFE_WRITE,
	AST_CFE_BOTH,
};

/*!
 * \brief Register a custom function
 */
#define ast_custom_function_register(acf) __ast_custom_function_register(acf, AST_MODULE_SELF)

/*!
 * \brief Register a custom function which requires escalated privileges.
 *
 * Examples would be SHELL() (for which a read needs permission to execute
 * arbitrary code) or FILE() (for which write needs permission to change files
 * on the filesystem).
 */
#define ast_custom_function_register_escalating(acf, escalation) __ast_custom_function_register_escalating(acf, escalation, AST_MODULE_SELF)

/*!
 * \brief Register a custom function
 */
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod);

/*!
 * \brief Register a custom function which requires escalated privileges.
 *
 * Examples would be SHELL() (for which a read needs permission to execute
 * arbitrary code) or FILE() (for which write needs permission to change files
 * on the filesystem).
 */
int __ast_custom_function_register_escalating(struct ast_custom_function *acf, enum ast_custom_function_escalation escalation, struct ast_module *mod);

/*!
 * \brief Retrieve the number of active calls
 */
int ast_active_calls(void);

/*!
 * \brief Retrieve the total number of calls processed through the PBX since last restart
 */
int ast_processed_calls(void);

/*!
 * \brief executes a read operation on a function
 *
 * \param chan Channel to execute on
 * \param function Data containing the function call string (will be modified)
 * \param workspace A pointer to safe memory to use for a return value
 * \param len the number of bytes in workspace
 *
 * This application executes a function in read mode on a given channel.
 *
 * \retval 0 success
 * \retval non-zero failure
 */
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len);

/*!
 * \brief executes a read operation on a function
 *
 * \param chan Channel to execute on
 * \param function Data containing the function call string (will be modified)
 * \param str A dynamic string buffer into which to place the result.
 * \param maxlen <0 if the dynamic buffer should not grow; >0 if the dynamic buffer should be limited to that number of bytes; 0 if the dynamic buffer has no upper limit
 *
 * This application executes a function in read mode on a given channel.
 *
 * \retval 0 success
 * \retval non-zero failure
 */
int ast_func_read2(struct ast_channel *chan, const char *function, struct ast_str **str, ssize_t maxlen);

/*!
 * \brief executes a write operation on a function
 *
 * \param chan Channel to execute on
 * \param function Data containing the function call string (will be modified)
 * \param value A value parameter to pass for writing
 *
 * This application executes a function in write mode on a given channel.
 *
 * \retval 0 success
 * \retval non-zero failure
 */
int ast_func_write(struct ast_channel *chan, const char *function, const char *value);

/*!
 * \details
 * When looking up extensions, we can have different requests
 * identified by the 'action' argument, as follows.
 *
 * \note that the coding is such that the low 4 bits are the
 * third argument to extension_match_core.
 */
enum ext_match_t {
	E_MATCHMORE = 	0x00,	/* extension can match but only with more 'digits' */
	E_CANMATCH =	0x01,	/* extension can match with or without more 'digits' */
	E_MATCH =	0x02,	/* extension is an exact match */
	E_MATCH_MASK =	0x03,	/* mask for the argument to extension_match_core() */
	E_SPAWN =	0x12,	/* want to spawn an extension. Requires exact match */
	E_FINDLABEL =	0x22	/* returns the priority for a given label. Requires exact match */
};

#define STATUS_NO_CONTEXT	1
#define STATUS_NO_EXTENSION	2
#define STATUS_NO_PRIORITY	3
#define STATUS_NO_LABEL		4
#define STATUS_SUCCESS		5

#ifdef LOW_MEMORY
#define AST_PBX_MAX_STACK  128
#else
#define AST_PBX_MAX_STACK  512
#endif

/* request and result for pbx_find_extension */
struct pbx_find_info {
#if 0
	const char *context;
	const char *exten;
	int priority;
#endif

	char *incstack[AST_PBX_MAX_STACK];      /* filled during the search */
	int stacklen;                   /* modified during the search */
	int status;                     /* set on return */
	struct ast_switch *swo;         /* set on return */
	const char *data;               /* set on return */
	const char *foundcontext;       /* set on return */
};

struct ast_exten *pbx_find_extension(struct ast_channel *chan,
									 struct ast_context *bypass, struct pbx_find_info *q,
									 const char *context, const char *exten, int priority,
									 const char *label, const char *callerid, enum ext_match_t action);

/*! \brief hashtable functions for contexts */
/*! @{ */
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
unsigned int ast_hashtab_hash_contexts(const void *obj);
/*! @} */

/*!
 * \brief Command completion for the list of installed applications.
 *
 * This can be called from a CLI command completion function that wants to
 * complete from the list of available applications.
 */
char *ast_complete_applications(const char *line, const char *word, int state);

/*!
 * \brief Enable/disable the execution of 'dangerous' functions from external
 * protocols (AMI, etc.).
 *
 * These dialplan functions (such as \c SHELL) provide an opportunity for
 * privilege escalation. They are okay to invoke from the dialplan, but external
 * protocols with permission controls should not normally invoke them.
 *
 * This function can globally enable/disable the execution of dangerous
 * functions from external protocols.
 *
 * \param new_live_dangerously If true, enable the execution of escalating
 * functions from external protocols.
 */
void pbx_live_dangerously(int new_live_dangerously);

/*!
 * \brief Inhibit (in the current thread) the execution of dialplan functions
 * which cause privilege escalations. If pbx_live_dangerously() has been
 * called, this function has no effect.
 *
 * \return 0 if successfuly marked current thread.
 * \return Non-zero if marking current thread failed.
 */
int ast_thread_inhibit_escalations(void);

/*!
 * \brief Swap the current thread escalation inhibit setting.
 * \since 11.24.0
 *
 * \param inhibit New setting.  Non-zero to inhibit.
 *
 * \retval 1 if dangerous function execution was inhibited.
 * \retval 0 if dangerous function execution was allowed.
 * \retval -1 on error.
 */
int ast_thread_inhibit_escalations_swap(int inhibit);

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif /* _ASTERISK_PBX_H */
