asterisk/include/asterisk/ccss.h

1598 lines
56 KiB
C

/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2010, Digium, Inc.
*
* Mark Michelson <mmichelson@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 Call Completion Supplementary Services API
* \author Mark Michelson <mmichelson@digium.com>
*/
#ifndef _ASTERISK_CCSS_H
#define _ASTERISK_CCSS_H
#include "asterisk.h"
#include "asterisk/linkedlists.h"
#include "asterisk/devicestate.h"
enum ast_cc_service_type {
/* No Service available/requested */
AST_CC_NONE,
/* Call Completion Busy Subscriber */
AST_CC_CCBS,
/* Call Completion No Response */
AST_CC_CCNR,
/* Call Completion Not Logged In (currently SIP only) */
AST_CC_CCNL,
};
/*!
* \since 1.8
* \brief The various possibilities for cc_agent_policy values
*/
enum ast_cc_agent_policies {
/*! Never offer CCSS to the caller */
AST_CC_AGENT_NEVER,
/*! Offer CCSS using native signaling */
AST_CC_AGENT_NATIVE,
/*! Use generic agent for caller */
AST_CC_AGENT_GENERIC,
};
/*!
* \brief agent flags that can alter core behavior
*/
enum ast_cc_agent_flags {
/* Some agent types allow for a caller to
* request CC without reaching the CC_CALLER_OFFERED
* state. In other words, the caller can request
* CC while he is still on the phone from the failed
* call. The generic agent is an agent which allows
* for this behavior.
*/
AST_CC_AGENT_SKIP_OFFER = (1 << 0),
};
/*!
* \since 1.8
* \brief The various possibilities for cc_monitor_policy values
*/
enum ast_cc_monitor_policies {
/*! Never accept CCSS offers from callee */
AST_CC_MONITOR_NEVER,
/* CCSS only available if callee offers it through signaling */
AST_CC_MONITOR_NATIVE,
/*! Always use CCSS generic monitor for callee
* Note that if callee offers CCSS natively, we still
* will use a generic CCSS monitor if this is set
*/
AST_CC_MONITOR_GENERIC,
/*! Accept native CCSS offers, but if no offer is present,
* use a generic CCSS monitor
*/
AST_CC_MONITOR_ALWAYS,
};
/* Forward declaration. Struct is in main/ccss.c */
struct ast_cc_config_params;
/*!
* \since 1.8
* \brief Queue an AST_CONTROL_CC frame
*
* \note
* Since this function calls ast_queue_frame, the channel will be
* locked during the course of this function.
*
* \param chan The channel onto which to queue the frame
* \param monitor_type The type of monitor to use when CC is requested
* \param dialstring The dial string used to call the device
* \param service The type of CC service the device is willing to offer
* \param private_data If a native monitor is being used, and some channel-driver-specific private
* data has been allocated, then this parameter should contain a pointer to that data. If using a generic
* monitor, this parameter should remain NULL. Note that if this function should fail at some point,
* it is the responsibility of the caller to free the private data upon return.
* \retval 0 Success
* \retval -1 Error
*/
int ast_queue_cc_frame(struct ast_channel *chan, const char * const monitor_type,
const char * const dialstring, enum ast_cc_service_type service, void *private_data);
/*!
* \brief Allocate and initialize an ast_cc_config_params structure
*
* \note
* Reasonable default values are chosen for the parameters upon allocation.
*
* \retval NULL Unable to allocate the structure
* \retval non-NULL A pointer to the newly allocated and initialized structure
*/
struct ast_cc_config_params *__ast_cc_config_params_init(const char *file, int line, const char *function);
/*!
* \brief Allocate and initialize an ast_cc_config_params structure
*
* \note
* Reasonable default values are chosen for the parameters upon allocation.
*
* \retval NULL Unable to allocate the structure
* \retval non-NULL A pointer to the newly allocated and initialized structure
*/
#define ast_cc_config_params_init() __ast_cc_config_params_init(__FILE__, __LINE__, __PRETTY_FUNCTION__)
/*!
* \brief Free memory from CCSS configuration params
*
* \note
* Just a call to ast_free for now...
*
* \param params Pointer to structure whose memory we need to free
*/
void ast_cc_config_params_destroy(struct ast_cc_config_params *params);
/*!
* \brief set a CCSS configuration parameter, given its name
*
* \note
* Useful when parsing config files when used in conjunction
* with ast_ccss_is_cc_config_param.
*
* \param params The parameter structure to set the value on
* \param name The name of the cc parameter
* \param value The value of the parameter
* \retval 0 Success
* \retval -1 Failure
*/
int ast_cc_set_param(struct ast_cc_config_params *params, const char * const name,
const char * value);
/*!
* \brief get a CCSS configuration parameter, given its name
*
* \note
* Useful when reading input as a string, like from dialplan or
* manager.
*
* \param params The CCSS configuration from which to get the value
* \param name The name of the CCSS parameter we want
* \param buf A preallocated buffer to hold the value
* \param buf_len The size of buf
* \retval 0 Success
* \retval -1 Failure
*/
int ast_cc_get_param(struct ast_cc_config_params *params, const char * const name,
char *buf, size_t buf_len);
/*!
* \since 1.8
* \brief Is this a CCSS configuration parameter?
* \param name Name of configuration option being parsed.
* \retval 1 Yes, this is a CCSS configuration parameter.
* \retval 0 No, this is not a CCSS configuration parameter.
*/
int ast_cc_is_config_param(const char * const name);
/*!
* \since 1.8
* \brief Set the specified CC config params to default values.
*
* \details
* This is just like ast_cc_copy_config_params() and could be used in place
* of it if you need to set the config params to defaults instead.
* You are simply "copying" defaults into the destination.
*
* \param params CC config params to set to default values.
*/
void ast_cc_default_config_params(struct ast_cc_config_params *params);
/*!
* \since 1.8
* \brief copy CCSS configuration parameters from one structure to another
*
* \details
* For now, this is a simple memcpy, but this function is necessary since
* the size of an ast_cc_config_params structure is unknown outside of
* main/ccss.c. Also, this allows for easier expansion of the function in
* case it becomes more complex than just a memcpy.
*
* \param src The structure from which data is copied
* \param dest The structure to which data is copied
*/
void ast_cc_copy_config_params(struct ast_cc_config_params *dest, const struct ast_cc_config_params *src);
/*!
* \since 1.8
* \brief Get the cc_agent_policy
* \param config The configuration to retrieve the policy from
* \return The current cc_agent_policy for this configuration
*/
enum ast_cc_agent_policies ast_get_cc_agent_policy(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_agent_policy
* \param config The configuration to set the cc_agent_policy on
* \param value The new cc_agent_policy we want to change to
* \retval 0 Success
* \retval -1 Failure (likely due to bad input)
*/
int ast_set_cc_agent_policy(struct ast_cc_config_params *config, enum ast_cc_agent_policies value);
/*!
* \since 1.8
* \brief Get the cc_monitor_policy
* \param config The configuration to retrieve the cc_monitor_policy from
* \return The cc_monitor_policy retrieved from the configuration
*/
enum ast_cc_monitor_policies ast_get_cc_monitor_policy(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_monitor_policy
* \param config The configuration to set the cc_monitor_policy on
* \param value The new cc_monitor_policy we want to change to
* \retval 0 Success
* \retval -1 Failure (likely due to bad input)
*/
int ast_set_cc_monitor_policy(struct ast_cc_config_params *config, enum ast_cc_monitor_policies value);
/*!
* \since 1.8
* \brief Get the cc_offer_timer
* \param config The configuration to retrieve the cc_offer_timer from
* \return The cc_offer_timer from this configuration
*/
unsigned int ast_get_cc_offer_timer(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_offer_timer
* \param config The configuration to set the cc_offer_timer on
* \param value The new cc_offer_timer we want to change to
*/
void ast_set_cc_offer_timer(struct ast_cc_config_params *config, unsigned int value);
/*!
* \since 1.8
* \brief Get the ccnr_available_timer
* \param config The configuration to retrieve the ccnr_available_timer from
* \return The ccnr_available_timer from this configuration
*/
unsigned int ast_get_ccnr_available_timer(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the ccnr_available_timer
* \param config The configuration to set the ccnr_available_timer on
* \param value The new ccnr_available_timer we want to change to
*/
void ast_set_ccnr_available_timer(struct ast_cc_config_params *config, unsigned int value);
/*!
* \since 1.8
* \brief Get the cc_recall_timer
* \param config The configuration to retrieve the cc_recall_timer from
* \return The cc_recall_timer from this configuration
*/
unsigned int ast_get_cc_recall_timer(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_recall_timer
* \param config The configuration to set the cc_recall_timer on
* \param value The new cc_recall_timer we want to change to
*/
void ast_set_cc_recall_timer(struct ast_cc_config_params *config, unsigned int value);
/*!
* \since 1.8
* \brief Get the ccbs_available_timer
* \param config The configuration to retrieve the ccbs_available_timer from
* \return The ccbs_available_timer from this configuration
*/
unsigned int ast_get_ccbs_available_timer(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the ccbs_available_timer
* \param config The configuration to set the ccbs_available_timer on
* \param value The new ccbs_available_timer we want to change to
*/
void ast_set_ccbs_available_timer(struct ast_cc_config_params *config, unsigned int value);
/*!
* \since 1.8
* \brief Get the cc_agent_dialstring
* \param config The configuration to retrieve the cc_agent_dialstring from
* \return The cc_agent_dialstring from this configuration
*/
const char *ast_get_cc_agent_dialstring(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_agent_dialstring
* \param config The configuration to set the cc_agent_dialstring on
* \param value The new cc_agent_dialstring we want to change to
*/
void ast_set_cc_agent_dialstring(struct ast_cc_config_params *config, const char *const value);
/*!
* \since 1.8
* \brief Get the cc_max_agents
* \param config The configuration to retrieve the cc_max_agents from
* \return The cc_max_agents from this configuration
*/
unsigned int ast_get_cc_max_agents(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_max_agents
* \param config The configuration to set the cc_max_agents on
* \param value The new cc_max_agents we want to change to
*/
void ast_set_cc_max_agents(struct ast_cc_config_params *config, unsigned int value);
/*!
* \since 1.8
* \brief Get the cc_max_monitors
* \param config The configuration to retrieve the cc_max_monitors from
* \return The cc_max_monitors from this configuration
*/
unsigned int ast_get_cc_max_monitors(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the cc_max_monitors
* \param config The configuration to set the cc_max_monitors on
* \param value The new cc_max_monitors we want to change to
*/
void ast_set_cc_max_monitors(struct ast_cc_config_params *config, unsigned int value);
/*!
* \since 1.8
* \brief Get the name of the callback_macro
* \param config The configuration to retrieve the callback_macro from
* \return The callback_macro name
*/
const char *ast_get_cc_callback_macro(struct ast_cc_config_params *config);
/*!
* \since 1.8
* \brief Set the callback_macro name
* \param config The configuration to set the callback_macro on
* \param value The new callback macro we want to change to
*/
void ast_set_cc_callback_macro(struct ast_cc_config_params *config, const char * const value);
/*!
* \since 11
* \brief Get the name of the callback subroutine
* \param config The configuration to retrieve the callback_sub from
* \return The callback_sub name
*/
const char *ast_get_cc_callback_sub(struct ast_cc_config_params *config);
/*!
* \since 11
* \brief Set the callback subroutine name
* \param config The configuration to set the callback_sub on
* \param value The new callback subroutine we want to change to
*/
void ast_set_cc_callback_sub(struct ast_cc_config_params *config, const char * const value);
/* END CONFIGURATION FUNCTIONS */
/* BEGIN AGENT/MONITOR REGISTRATION API */
struct ast_cc_monitor_callbacks;
/*!
* \since 1.8
* \brief Register a set of monitor callbacks with the core
*
* \details
* This is made so that at monitor creation time, the proper callbacks
* may be installed and the proper .init callback may be called for the
* monitor to establish private data.
*
* \param callbacks The callbacks used by the monitor implementation
* \retval 0 Successfully registered
* \retval -1 Failure to register
*/
int ast_cc_monitor_register(const struct ast_cc_monitor_callbacks *callbacks);
/*!
* \since 1.8
* \brief Unregister a set of monitor callbacks with the core
*
* \details
* If a module which makes use of a CC monitor is unloaded, then it may
* unregister its monitor callbacks with the core.
*
* \param callbacks The callbacks used by the monitor implementation
*/
void ast_cc_monitor_unregister(const struct ast_cc_monitor_callbacks *callbacks);
struct ast_cc_agent_callbacks;
/*!
* \since 1.8
* \brief Register a set of agent callbacks with the core
*
* \details
* This is made so that at agent creation time, the proper callbacks
* may be installed and the proper .init callback may be called for the
* monitor to establish private data.
*
* \param callbacks The callbacks used by the agent implementation
* \retval 0 Successfully registered
* \retval -1 Failure to register
*/
int ast_cc_agent_register(const struct ast_cc_agent_callbacks *callbacks);
/*!
* \since 1.8
* \brief Unregister a set of agent callbacks with the core
*
* \details
* If a module which makes use of a CC agent is unloaded, then it may
* unregister its agent callbacks with the core.
*
* \param callbacks The callbacks used by the agent implementation
*/
void ast_cc_agent_unregister(const struct ast_cc_agent_callbacks *callbacks);
/* END AGENT/MONITOR REGISTRATION API */
/* BEGIN SECTION ON MONITORS AND MONITOR CALLBACKS */
/*!
* It is recommended that monitors use a pointer to
* an ast_cc_monitor_callbacks::type when creating
* an AST_CONTROL_CC frame. Since the generic monitor
* callbacks are opaque and channel drivers will wish
* to use that, this string is made globally available
* for all to use
*/
#define AST_CC_GENERIC_MONITOR_TYPE "generic"
/*!
* Used to determine which type
* of monitor an ast_cc_device_monitor
* is.
*/
enum ast_cc_monitor_class {
AST_CC_DEVICE_MONITOR,
AST_CC_EXTENSION_MONITOR,
};
/*!
* \internal
* \brief An item in a CC interface tree.
*
* These are the individual items in an interface tree.
* The key difference between this structure and the ast_cc_interface
* is that this structure contains data which is intrinsic to the item's
* placement in the tree, such as who its parent is.
*/
struct ast_cc_monitor {
/*!
* Information regarding the interface.
*/
struct ast_cc_interface *interface;
/*!
* Every interface has an id that uniquely identifies it. It is
* formed by incrementing a counter.
*/
unsigned int id;
/*!
* The ID of this monitor's parent. If this monitor is at the
* top of the tree, then his parent will be 0.
*/
unsigned int parent_id;
/*!
* The instance of the CC core to which this monitor belongs
*/
int core_id;
/*!
* The type of call completion service offered by a device.
*/
enum ast_cc_service_type service_offered;
/*!
* \brief Name that should be used to recall specified interface
*
* \details
* When issuing a CC recall, some technologies will require
* that a name other than the device name is dialed. For instance,
* with SIP, a specific URI will be used which sip will be able
* to recognize as being a CC recall. Similarly, ISDN will need a specific
* dial string to know that the call is a recall.
*/
char *dialstring;
/*!
* The ID of the available timer used by the current monitor
*/
int available_timer_id;
/*!
* Monitor callbacks
*/
const struct ast_cc_monitor_callbacks *callbacks;
/*!
* \brief Data that is private to a monitor technology
*
* Most channel drivers that implement CC monitors will have to
* allocate data that the CC core does not care about but which
* is vital to the operation of the monitor. This data is stored
* in this pointer so that the channel driver may use it as
* needed
*/
void *private_data;
AST_LIST_ENTRY(ast_cc_monitor) next;
};
/*!
* \brief Callbacks defined by CC monitors
*
* \note
* Every callback is called with the list of monitors locked. There
* are several public API calls that also will try to lock this lock.
* These public functions have a note in their doxygen stating so.
* As such, pay attention to the lock order you establish in these callbacks
* to ensure that you do not violate the lock order when calling
* the functions in this file with lock order notices.
*/
struct ast_cc_monitor_callbacks {
/*!
* \brief Type of monitor the callbacks belong to.
*
* \note
* Examples include "generic" and "SIP"
*/
const char *type;
/*!
* \brief Request CCSS.
*
* \param monitor CC core monitor control.
* \param available_timer_id The scheduler ID for the available timer.
* Will never be NULL for a device monitor.
*
* \details
* Perform whatever steps are necessary in order to request CC.
* In addition, the monitor implementation is responsible for
* starting the available timer in this callback.
*
* \retval 0 on success
* \retval -1 on failure.
*/
int (*request_cc)(struct ast_cc_monitor *monitor, int *available_timer_id);
/*!
* \brief Suspend monitoring.
*
* \param monitor CC core monitor control.
*
* \details
* Implementers must perform the necessary steps to suspend
* monitoring.
*
* \retval 0 on success
* \retval -1 on failure.
*/
int (*suspend)(struct ast_cc_monitor *monitor);
/*!
* \brief Status response to an ast_cc_monitor_status_request().
*
* \param monitor CC core monitor control.
* \param devstate Current status of a Party A device.
*
* \details
* Alert a monitor as to the status of the agent for which
* the monitor had previously requested a status request.
*
* \note Zero or more responses may come as a result.
*
* \retval 0 on success
* \retval -1 on failure.
*/
int (*status_response)(struct ast_cc_monitor *monitor, enum ast_device_state devstate);
/*!
* \brief Unsuspend monitoring.
*
* \param monitor CC core monitor control.
*
* \details
* Perform the necessary steps to unsuspend monitoring.
*
* \retval 0 on success
* \retval -1 on failure.
*/
int (*unsuspend)(struct ast_cc_monitor *monitor);
/*!
* \brief Cancel the running available timer.
*
* \param monitor CC core monitor control.
* \param sched_id Available timer scheduler id to cancel.
* Will never be NULL for a device monitor.
*
* \details
* In most cases, this function will likely consist of just a
* call to AST_SCHED_DEL. It might have been possible to do this
* within the core, but unfortunately the mixture of sched_thread
* and sched usage in Asterisk prevents such usage.
*
* \retval 0 on success
* \retval -1 on failure.
*/
int (*cancel_available_timer)(struct ast_cc_monitor *monitor, int *sched_id);
/*!
* \brief Destroy private data on the monitor.
*
* \param private_data The private data pointer from the monitor.
*
* \details
* Implementers of this callback are responsible for destroying
* all heap-allocated data in the monitor's private_data pointer, including
* the private_data itself.
*/
void (*destructor)(void *private_data);
};
/*!
* \since 1.8
* \brief Scheduler callback for available timer expiration
*
* \note
* When arming the available timer from within a device monitor, you MUST
* use this function as the callback for the scheduler.
*
* \param data A reference to the CC monitor on which the timer was running.
*/
int ast_cc_available_timer_expire(const void *data);
/* END SECTION ON MONITORS AND MONITOR CALLBACKS */
/* BEGIN API FOR IN-CALL CC HANDLING */
/*!
* \since 1.8
*
* \brief Mark the channel to ignore further CC activity.
*
* \details
* When a CC-capable application, such as Dial, has finished
* with all CC processing for a channel and knows that any further
* CC processing should be ignored, this function should be called.
*
* \param chan The channel for which further CC processing should be ignored.
*/
void ast_ignore_cc(struct ast_channel *chan);
/*!
* \since 1.8
*
* \brief Properly react to a CC control frame.
*
* \details
* When a CC-capable application, such as Dial, receives a frame
* of type AST_CONTROL_CC, then it may call this function in order
* to have the device which sent the frame added to the tree of interfaces
* which is kept on the inbound channel.
*
* \param inbound The inbound channel
* \param outbound The outbound channel (The one from which the CC frame was read)
* \param frame_data The ast_frame's data.ptr field.
*/
void ast_handle_cc_control_frame(struct ast_channel *inbound, struct ast_channel *outbound, void *frame_data);
/*!
* \since 1.8
*
* \brief Start the CC process on a call.
*
* \details
* Whenever a CC-capable application, such as Dial, wishes to
* engage in CC activity, it initiates the process by calling this
* function. If the CC core should discover that a previous application
* has called ast_ignore_cc on this channel or a "parent" channel, then
* the value of the ignore_cc integer passed in will be set nonzero.
*
* The ignore_cc parameter is a convenience parameter. It can save an
* application the trouble of trying to call CC APIs when it knows that
* it should just ignore further attempts at CC actions.
*
* \param chan The inbound channel calling the CC-capable application.
* \param[out] ignore_cc Will be set non-zero if no further CC actions need to be taken
* \retval 0 Success
* \retval -1 Failure
*/
int ast_cc_call_init(struct ast_channel *chan, int *ignore_cc);
/*!
* \since 1.8
*
* \brief Add a child dialstring to an extension monitor
*
* Whenever we request a channel, the parent extension monitor needs
* to store the dialstring of the device requested. The reason is so
* that we can call the device back during the recall even if we are
* not monitoring the device.
*
* \param incoming The caller's channel
* \param dialstring The dialstring used when requesting the outbound channel
* \param device_name The device name associated with the requested outbound channel
*/
void ast_cc_extension_monitor_add_dialstring(struct ast_channel *incoming, const char * const dialstring, const char * const device_name);
/*!
* \since 1.8
* \brief Check if the incoming CC request is within the bounds
* set by the cc_max_requests configuration option
*
* \details
* It is recommended that an entity which receives an incoming
* CC request calls this function before calling
* ast_cc_agent_accept_request. This way, immediate feedback can be
* given to the caller about why his request was rejected.
*
* If this is not called and a state change to CC_CALLER_REQUESTED
* is made, then the core will still not allow for the request
* to succeed. However, if done this way, it may not be obvious
* to the requestor why the request failed.
*
* \retval 0 Not within the limits. Fail.
* \retval non-zero Within the limits. Success.
*/
int ast_cc_request_is_within_limits(void);
/*!
* \since 1.8
* \brief Get the core id for the current call
*
* \details
* The main use of this function is for channel drivers
* who queue an AST_CONTROL_CC frame. A channel driver may
* call this function in order to get the core_id for what
* may become a CC request. This way, when monitor functions
* are called which use a core_id as a means of identification,
* the channel driver will have saved this information.
*
* The channel given to this function may be an inbound or outbound
* channel. Both will have the necessary info on it.
*
* \param chan The channel from which to get the core_id.
* \retval core_id on success
* \retval -1 Failure
*/
int ast_cc_get_current_core_id(struct ast_channel *chan);
/* END API FOR IN-CALL CC HANDLING */
/*!
* \brief Structure with information about an outbound interface
*
* \details
* This structure is first created when an outbound interface indicates that
* it is capable of accepting a CC request. It is stored in a "tree" on a datastore on
* the caller's channel. Once an agent structure is created, the agent gains
* a reference to the tree of interfaces. If CC is requested, then the
* interface tree on the agent is converted into a tree of monitors. Each
* monitor will contain a pointer to an individual ast_cc_interface. Finally,
* the tree of interfaces is also present on a second datastore during a
* CC recall so that the CC_INTERFACES channel variable may be properly
* populated.
*/
struct ast_cc_interface {
/* What class of monitor is being offered here
*/
enum ast_cc_monitor_class monitor_class;
/*!
* \brief The type of monitor that should be used for this interface
*
* \details
* This will be something like "extension" "generic" or "SIP".
* This should point to a static const char *, so there is
* no reason to make a new copy.
*/
const char *monitor_type;
/*!
* The configuration parameters used for this interface
*/
struct ast_cc_config_params *config_params;
/* The name of the interface/extension. local channels will
* have 'exten@context' for a name. Other channel types will
* have 'tech/device' for a name.
*/
char device_name[1];
};
/* BEGIN STRUCTURES FOR AGENTS */
struct ast_cc_agent {
/*!
* Which instance of the core state machine does this
* agent pertain to?
*/
unsigned int core_id;
/*!
* Callback functions needed for specific agent
* implementations
*/
const struct ast_cc_agent_callbacks *callbacks;
/*!
* Configuration parameters that affect this
* agent's operation.
*/
struct ast_cc_config_params *cc_params;
/*!
* \brief Flags for agent operation
*
* \details
* There are some attributes of certain agent types
* that can alter the behavior of certain CC functions.
* For a list of these flags, see the ast_cc_agent_flags
* enum
*/
unsigned int flags;
/*! Data specific to agent implementation */
void *private_data;
/*! The name of the device which this agent
* represents/communicates with
*/
char device_name[1];
};
enum ast_cc_agent_response_reason {
/*! CC request accepted */
AST_CC_AGENT_RESPONSE_SUCCESS,
/*! CC request not allowed at this time. Invalid state transition. */
AST_CC_AGENT_RESPONSE_FAILURE_INVALID,
/*! Too many CC requests in the system. */
AST_CC_AGENT_RESPONSE_FAILURE_TOO_MANY,
};
struct ast_cc_agent_callbacks {
/*!
* \brief Type of agent the callbacks belong to.
*
* \note
* Examples are "SIP" "ISDN" and "generic"
*/
const char *type;
/*!
* \brief CC agent initialization.
*
* \param agent CC core agent control.
* \param chan Original channel the agent will attempt to recall.
*
* \details
* This callback is called when the CC core
* is initialized. Agents should allocate
* any private data necessary for the
* call and assign it to the private_data
* on the agent. Additionally, if any ast_cc_agent_flags
* are pertinent to the specific agent type, they should
* be set in this function as well.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*init)(struct ast_cc_agent *agent, struct ast_channel *chan);
/*!
* \brief Start the offer timer.
*
* \param agent CC core agent control.
*
* \details
* This is called by the core when the caller hangs up after
* a call for which CC may be requested. The agent should
* begin the timer as configured.
*
* The primary reason why this functionality is left to
* the specific agent implementations is due to the differing
* use of schedulers throughout the code. Some channel drivers
* may already have a scheduler context they wish to use, and
* amongst those, some may use the ast_sched API while others
* may use the ast_sched_thread API, which are incompatible.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*start_offer_timer)(struct ast_cc_agent *agent);
/*!
* \brief Stop the offer timer.
*
* \param agent CC core agent control.
*
* \details
* This callback is called by the CC core when the caller
* has requested CC.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*stop_offer_timer)(struct ast_cc_agent *agent);
/*!
* \brief Respond to a CC request.
*
* \param agent CC core agent control.
* \param reason CC request response status.
*
* \details
* When the core receives knowledge that a called
* party has accepted a CC request, it will call
* this callback. The core may also call this
* if there is some error when attempting to process
* the incoming CC request.
*
* The duty of this is to issue a propper response to a
* CC request from the caller by acknowledging receipt
* of that request or rejecting it.
*/
void (*respond)(struct ast_cc_agent *agent, enum ast_cc_agent_response_reason reason);
/*!
* \brief Request the status of the agent's device.
*
* \param agent CC core agent control.
*
* \details
* Asynchronous request for the status of any caller
* which may be a valid caller for the CC transaction.
* Status responses should be made using the
* ast_cc_status_response function.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*status_request)(struct ast_cc_agent *agent);
/*!
* \brief Request for an agent's phone to stop ringing.
*
* \param agent CC core agent control.
*
* \details
* The usefulness of this is quite limited. The only specific
* known case for this is if Asterisk requests CC over an ISDN
* PTMP link as the TE side. If other phones are in the same
* recall group as the Asterisk server, and one of those phones
* picks up the recall notice, then Asterisk will receive a
* "stop ringing" notification from the NT side of the PTMP
* link. This indication needs to be passed to the phone
* on the other side of the Asterisk server which originally
* placed the call so that it will stop ringing. Since the
* phone may be of any type, it is necessary to have a callback
* that the core can know about.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*stop_ringing)(struct ast_cc_agent *agent);
/*!
* \brief Let the caller know that the callee has become free
* but that the caller cannot attempt to call back because
* he is either busy or there is congestion on his line.
*
* \param agent CC core agent control.
*
* \details
* This is something that really only affects a scenario where
* a phone places a call over ISDN PTMP to Asterisk, who then
* connects over PTMP again to the ISDN network. For most agent
* types, there is no need to implement this callback at all
* because they don't really need to actually do anything in
* this situation. If you're having trouble understanding what
* the purpose of this callback is, then you can be safe simply
* not implementing it.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*party_b_free)(struct ast_cc_agent *agent);
/*!
* \brief Begin monitoring a busy device.
*
* \param agent CC core agent control.
*
* \details
* The core will call this callback if the callee becomes
* available but the caller has reported that he is busy.
* The agent should begin monitoring the caller's device.
* When the caller becomes available again, the agent should
* call ast_cc_agent_caller_available.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*start_monitoring)(struct ast_cc_agent *agent);
/*!
* \brief Alert the caller that it is time to try recalling.
*
* \param agent CC core agent control.
*
* \details
* The core will call this function when it receives notice
* that a monitored party has become available.
*
* The agent's job is to send a message to the caller to
* notify it of such a change. If the agent is able to
* discern that the caller is currently unavailable, then
* the agent should react by calling the ast_cc_caller_unavailable
* function.
*
* \retval 0 on success.
* \retval -1 on error.
*/
int (*callee_available)(struct ast_cc_agent *agent);
/*!
* \brief Destroy private data on the agent.
*
* \param agent CC core agent control.
*
* \details
* The core will call this function upon completion
* or failure of CC.
*
* \note
* The agent private_data pointer may be NULL if the agent
* constructor failed.
*/
void (*destructor)(struct ast_cc_agent *agent);
};
/*!
* \brief Call a callback on all agents of a specific type
*
* \details
* Since the container of CC core instances is private, and so
* are the items which the container contains, we have to provide
* an ao2_callback-like method so that a specific agent may be
* found or so that an operation can be made on all agents of
* a particular type. The first three arguments should be familiar
* to anyone who has used ao2_callback. The final argument is the
* type of agent you wish to have the callback called on.
*
* \note Since agents are refcounted, and this function returns
* a reference to the agent, it is imperative that you decrement
* the refcount of the agent once you have finished using it.
*
* \param flags astobj2 search flags
* \param function an ao2 callback function to call
* \param arg the argument to the callback function
* \param type The type of agents to call the callback on
*/
struct ast_cc_agent *ast_cc_agent_callback(int flags, ao2_callback_fn *function, void *arg, const char * const type);
/* END STRUCTURES FOR AGENTS */
/* BEGIN STATE CHANGE API */
/*!
* \since 1.8
* \brief Offer CC to a caller
*
* \details
* This function is called from ast_hangup if the caller is
* eligible to be offered call completion service.
*
* \param caller_chan The calling channel
* \retval -1 Error
* \retval 0 Success
*/
int ast_cc_offer(struct ast_channel *caller_chan);
/*!
* \since 1.8
* \brief Accept inbound CC request
*
* \details
* When a caller requests CC, this function should be called to let
* the core know that the request has been accepted.
*
* \param core_id core_id of the CC transaction
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_agent_accept_request(int core_id, const char * const debug, ...);
/*!
* \since 1.8
* \brief Indicate that an outbound entity has accepted our CC request
*
* \details
* When we receive confirmation that an outbound device has accepted the
* CC request we sent it, this function must be called.
*
* \param core_id core_id of the CC transaction
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_monitor_request_acked(int core_id, const char * const debug, ...);
/*!
* \since 1.8
* \brief Indicate that the caller is busy
*
* \details
* When the callee makes it known that he is available, the core
* will let the caller's channel driver know that it may attempt
* to let the caller know to attempt a recall. If the channel
* driver can detect, though, that the caller is busy, then
* the channel driver should call this function to let the CC
* core know.
*
* \param core_id core_id of the CC transaction
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_agent_caller_busy(int core_id, const char * const debug, ...);
/*!
* \since 1.8
* \brief Indicate that a previously unavailable caller has become available
*
* \details
* If a monitor is suspended due to a caller becoming unavailable, then this
* function should be called to indicate that the caller has become available.
*
* \param core_id core_id of the CC transaction
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_agent_caller_available(int core_id, const char * const debug, ...);
/*!
* \since 1.8
* \brief Tell the CC core that a caller is currently recalling
*
* \details
* The main purpose of this is so that the core can alert the monitor
* to stop its available timer since the caller has begun its recall
* phase.
*
* \param core_id core_id of the CC transaction
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_agent_recalling(int core_id, const char * const debug, ...);
/*!
* \since 1.8
* \brief Indicate recall has been acknowledged
*
* \details
* When we receive confirmation that an endpoint has responded to our
* CC recall, we call this function.
*
* \param chan The inbound channel making the CC recall
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_completed(struct ast_channel *chan, const char * const debug, ...);
/*!
* \since 1.8
* \brief Indicate failure has occurred
*
* \details
* If at any point a failure occurs, this is the function to call
* so that the core can initiate cleanup procedures.
*
* \param core_id core_id of the CC transaction
* \param debug optional string to print for debugging purposes
* \retval 0 Success
* \retval -1 Failure
*/
int __attribute__((format(printf, 2, 3))) ast_cc_failed(int core_id, const char * const debug, ...);
/*!
* \since 1.8
* \brief Indicate that a failure has occurred on a specific monitor
*
* \details
* If a monitor should detect that a failure has occurred when communicating
* with its endpoint, then ast_cc_monitor_failed should be called. The big
* difference between ast_cc_monitor_failed and ast_cc_failed is that ast_cc_failed
* indicates a global failure for a CC transaction, where as ast_cc_monitor_failed
* is localized to a particular monitor. When ast_cc_failed is called, the entire
* CC transaction is torn down. When ast_cc_monitor_failed is called, only the
* monitor on which the failure occurred is pruned from the tree of monitors.
*
* If there are no more devices left to monitor when this function is called,
* then the core will fail the CC transaction globally.
*
* \param core_id The core ID for the CC transaction
* \param monitor_name The name of the monitor on which the failure occurred
* \param debug A debug message to print to the CC log
*/
int __attribute__((format(printf, 3, 4))) ast_cc_monitor_failed(int core_id, const char * const monitor_name, const char * const debug, ...);
/* END STATE CHANGE API */
/*!
* The following are all functions which are required due to the unique
* case where Asterisk is acting as the NT side of an ISDN PTMP
* connection to the caller and as the TE side of an ISDN PTMP connection
* to the callee. In such a case, there are several times where the
* PTMP monitor needs information from the agent in order to formulate
* the appropriate messages to send.
*/
/*!
* \brief Request the status of a caller or callers.
*
* \details
* When an ISDN PTMP monitor senses that the callee has become
* available, it needs to know the current status of the caller
* in order to determine the appropriate response to send to
* the caller. In order to do this, the monitor calls this function.
* Responses will arrive asynchronously.
*
* \note Zero or more responses may come as a result.
*
* \param core_id The core ID of the CC transaction
*
* \retval 0 Successfully requested status
* \retval -1 Failed to request status
*/
int ast_cc_monitor_status_request(int core_id);
/*!
* \brief Response with a caller's current status
*
* \details
* When an ISDN PTMP monitor requests the caller's status, the
* agent must respond to the request using this function. For
* simplicity it is recommended that the devstate parameter
* be one of AST_DEVICE_INUSE or AST_DEVICE_NOT_INUSE.
*
* \param core_id The core ID of the CC transaction
* \param devstate The current state of the caller to which the agent pertains
* \retval 0 Successfully responded with our status
* \retval -1 Failed to respond with our status
*/
int ast_cc_agent_status_response(int core_id, enum ast_device_state devstate);
/*!
* \brief Alert a caller to stop ringing
*
* \details
* When an ISDN PTMP monitor becomes available, it is assumed
* that the agent will then cause the caller's phone to ring. In
* some cases, this is literally what happens. In other cases, it may
* be that the caller gets a visible indication on his phone that he
* may attempt to recall the callee. If multiple callers are recalled
* (since it may be possible to have a group of callers configured as
* a single party A), and one of those callers picks up his phone, then
* the ISDN PTMP monitor will alert the other callers to stop ringing.
* The agent's stop_ringing callback will be called, and it is up to the
* agent's driver to send an appropriate message to make his caller
* stop ringing.
*
* \param core_id The core ID of the CC transaction
* \retval 0 Successfully requested for the phone to stop ringing
* \retval -1 Could not request for the phone to stop ringing
*/
int ast_cc_monitor_stop_ringing(int core_id);
/*!
* \brief Alert a caller that though the callee has become free, the caller
* himself is not and may not call back.
*
* \details
* When an ISDN PTMP monitor senses that his monitored party has become
* available, he will request the status of the called party. If he determines
* that the caller is currently not available, then he will call this function
* so that an appropriate message is sent to the caller.
*
* Yes, you just read that correctly. The callee asks the caller what his
* current status is, and if the caller is currently unavailable, the monitor
* must send him a message anyway. WTF?
*
* This function results in the agent's party_b_free callback being called.
* It is most likely that you will not need to actually implement the
* party_b_free callback in an agent because it is not likely that you will
* need to or even want to send a caller a message indicating the callee's
* status if the caller himself is not also free.
*
* \param core_id The core ID of the CC transaction
* \retval 0 Successfully alerted the core that party B is free
* \retval -1 Could not alert the core that party B is free
*/
int ast_cc_monitor_party_b_free(int core_id);
/* BEGIN API FOR USE WITH/BY MONITORS */
/*!
* \since 1.8
* \brief Return the number of outstanding CC requests to a specific device
*
* \note
* This function will lock the list of monitors stored on every instance of
* the CC core. Callers of this function should be aware of this and avoid
* any potential lock ordering problems.
*
* \param name The name of the monitored device
* \param type The type of the monitored device (e.g. "generic")
* \return The number of CC requests for the monitor
*/
int ast_cc_monitor_count(const char * const name, const char * const type);
/*!
* \since 1.8
* \brief Alert the core that a device being monitored has become available.
*
* \note
* The code in the core will take care of making sure that the information gets passed
* up the ladder correctly.
*
* \par core_id The core ID of the corresponding CC transaction
* \par debug
* \retval 0 Request successfully queued
* \retval -1 Request could not be queued
*/
int __attribute__((format(printf, 2, 3))) ast_cc_monitor_callee_available(const int core_id, const char * const debug, ...);
/* END API FOR USE WITH/BY MONITORS */
/* BEGIN API TO BE USED ON CC RECALL */
/*!
* \since 1.8
* \brief Set up a CC recall datastore on a channel
*
* \details
* Implementers of protocol-specific CC agents will need to call this
* function in order for the channel to have the necessary interfaces
* to recall.
*
* This function must be called by the implementer once it has been detected
* that an inbound call is a cc_recall. After allocating the channel, call this
* function, followed by ast_cc_set_cc_interfaces_chanvar. While it would be nice to
* be able to have the core do this automatically, it just cannot be done given
* the current architecture.
*/
int ast_setup_cc_recall_datastore(struct ast_channel *chan, const int core_id);
/*!
* \since 1.8
* \brief Decide if a call to a particular channel is a CC recall
*
* \details
* When a CC recall happens, it is important on the called side to
* know that the call is a CC recall and not a normal call. This function
* will determine first if the call in question is a CC recall. Then it
* will determine based on the chan parameter if the channel is being
* called is being recalled.
*
* As a quick example, let's say a call is placed to SIP/1000 and SIP/1000
* is currently on the phone. The caller requests CCBS. SIP/1000 finishes
* his call, and so the caller attempts to recall. Now, the dialplan
* administrator has set up this second call so that not only is SIP/1000
* called, but also SIP/2000 is called. If SIP/1000's channel were passed
* to this function, the return value would be non-zero, but if SIP/2000's
* channel were passed into this function, then the return would be 0 since
* SIP/2000 was not one of the original devices dialed.
*
* \note
* This function may be called on a calling channel as well to
* determine if it is part of a CC recall.
*
* \note
* This function will lock the channel as well as the list of monitors
* on the channel datastore, though the locks are not held at the same time. Be
* sure that you have no potential lock order issues here.
*
* \param chan The channel to check
* \param[out] core_id If this is a valid CC recall, the core_id of the failed call
* will be placed in this output parameter
* \param monitor_type Clarify which type of monitor type we are looking for if this
* is happening on a called channel. For incoming channels, this parameter is not used.
* \retval 0 Either this is not a recall or it is but this channel is not part of the recall
* \retval non-zero This is a recall and the channel in question is directly involved.
*/
int ast_cc_is_recall(struct ast_channel *chan, int *core_id, const char * const monitor_type);
/*!
* \since 1.8
* \brief Get the associated monitor given the device name and core_id
*
* \details
* The function ast_cc_is_recall is helpful for determining if a call to
* a specific channel is a recall. However, once you have determined that
* this is a recall, you will most likely need access to the private data
* within the associated monitor. This function is what one uses to get
* that monitor.
*
* \note
* This function locks the list of monitors that correspond to the core_id
* passed in. Be sure that you have no potential lock order issues when
* calling this function.
*
* \param core_id The core ID to which this recall corresponds. This likely will
* have been obtained using the ast_cc_is_recall function
* \param device_name Which device to find the monitor for.
*
* \retval NULL Appropriate monitor does not exist
* \retval non-NULL The monitor to use for this recall
*/
struct ast_cc_monitor *ast_cc_get_monitor_by_recall_core_id(const int core_id, const char * const device_name);
/*!
* \since 1.8
* \brief Set the first level CC_INTERFACES channel variable for a channel.
*
* \note
* Implementers of protocol-specific CC agents should call this function after
* calling ast_setup_cc_recall_datastore.
*
* \note
* This function will lock the channel as well as the list of monitors stored
* on the channel's CC recall datastore, though neither are held at the same
* time. Callers of this function should be aware of potential lock ordering
* problems that may arise.
*
* \details
* The CC_INTERFACES channel variable will have the interfaces that should be
* called back for a specific PBX instance.
*
* \param chan The channel to set the CC_INTERFACES variable on
*/
int ast_cc_agent_set_interfaces_chanvar(struct ast_channel *chan);
/*!
* \since 1.8
* \brief Set the CC_INTERFACES channel variable for a channel using an
* \verbatim extension@context \endverbatim as a starting point
*
* \details
* The CC_INTERFACES channel variable will have the interfaces
* that should be called back for a specific PBX instance. This
* version of the function is used mainly by local channels,
* wherein we need to set CC_INTERFACES based on an extension
* and context that appear in the middle of the tree of dialed
* interfaces.
*
* \note
* This function will lock the channel as well as the list of monitors stored
* on the channel's CC recall datastore, though neither are held at the same
* time. Callers of this function should be aware of potential lock ordering
* problems that may arise.
*
* \param chan The channel to set the CC_INTERFACES variable on
* \param extension The name of the extension for which we're setting the variable.
* This should be in the form of \verbatim exten@context \endverbatim
*/
int ast_set_cc_interfaces_chanvar(struct ast_channel *chan, const char * const extension);
/*!
* \since 1.8
* \brief Make CCBS available in the case that ast_call fails
*
* In some situations, notably if a call-limit is reached in SIP, ast_call will fail
* due to Asterisk's knowing that the desired device is currently busy. In such a situation,
* CCBS should be made available to the caller.
*
* One caveat is that this may only be used if generic monitoring is being used. The reason
* is that since Asterisk determined that the device was busy without actually placing a call to it,
* the far end will have no idea what call we are requesting call completion for if we were to send
* a call completion request.
*/
void ast_cc_call_failed(struct ast_channel *incoming, struct ast_channel *outgoing, const char * const dialstring);
/*!
* \since 1.8
* \brief Callback made from ast_cc_callback for certain channel types
*
* \param inbound Incoming asterisk channel.
* \param cc_params The CC configuration parameters for the outbound target
* \param monitor_type The type of monitor to use when CC is requested
* \param device_name The name of the outbound target device.
* \param dialstring The dial string used when calling this specific interface
* \param private_data If a native monitor is being used, and some channel-driver-specific private
* data has been allocated, then this parameter should contain a pointer to that data. If using a generic
* monitor, this parameter should remain NULL. Note that if this function should fail at some point,
* it is the responsibility of the caller to free the private data upon return.
*
* \details
* For channel types that fail ast_request when the device is busy, we call into the
* channel driver with ast_cc_callback. This is the callback that is called in that
* case for each device found which could have been returned by ast_request.
*
* This function creates a CC control frame payload, simulating the act of reading
* it from the nonexistent outgoing channel's frame queue. We then handle this
* simulated frame just as we would a normal CC frame which had actually been queued
* by the channel driver.
*/
void ast_cc_busy_interface(struct ast_channel *inbound, struct ast_cc_config_params *cc_params,
const char *monitor_type, const char * const device_name, const char * const dialstring, void *private_data);
/*!
* \since 1.8
* \brief Create a CC Control frame
*
* \details
* chan_dahdi is weird. It doesn't seem to actually queue frames when it needs to tell
* an application something. Instead it wakes up, tells the application that it has data
* ready, and then based on set flags, creates the proper frame type. For chan_dahdi, we
* provide this function. It provides us the data we need, and we'll make its frame for it.
*
* \param chan A channel involved in the call. What we want is on a datastore on both incoming
* and outgoing so either may be provided
* \param cc_params The CC configuration parameters for the outbound target
* \param monitor_type The type of monitor to use when CC is requested
* \param device_name The name of the outbound target device.
* \param dialstring The dial string used when calling this specific interface
* \param service What kind of CC service is being offered. (CCBS/CCNR/etc...)
* \param private_data If a native monitor is being used, and some channel-driver-specific private
* data has been allocated, then this parameter should contain a pointer to that data. If using a generic
* monitor, this parameter should remain NULL. Note that if this function should fail at some point,
* it is the responsibility of the caller to free the private data upon return.
* \param[out] frame The frame we will be returning to the caller. It is vital that ast_frame_free be
* called on this frame since the payload will be allocated on the heap.
* \retval -1 Failure. At some point there was a failure. Do not attempt to use the frame in this case.
* \retval 0 Success
*/
int ast_cc_build_frame(struct ast_channel *chan, struct ast_cc_config_params *cc_params,
const char *monitor_type, const char * const device_name,
const char * const dialstring, enum ast_cc_service_type service, void *private_data,
struct ast_frame *frame);
/*!
* \brief Callback made from ast_cc_callback for certain channel types
* \since 1.8
*
* \param chan A channel involved in the call. What we want is on a datastore on both incoming and outgoing so either may be provided
* \param cc_params The CC configuration parameters for the outbound target
* \param monitor_type The type of monitor to use when CC is requested
* \param device_name The name of the outbound target device.
* \param dialstring The dial string used when calling this specific interface
* \param private_data If a native monitor is being used, and some channel-driver-specific private
* data has been allocated, then this parameter should contain a pointer to that data. If using a generic
* monitor, this parameter should remain NULL. Note that if this function should fail at some point,
* it is the responsibility of the caller to free the private data upon return.
*
* \details
* For channel types that fail ast_request when the device is busy, we call into the
* channel driver with ast_cc_callback. This is the callback that is called in that
* case for each device found which could have been returned by ast_request.
*/
typedef void (*ast_cc_callback_fn)(struct ast_channel *chan, struct ast_cc_config_params *cc_params,
const char *monitor_type, const char * const device_name, const char * const dialstring, void *private_data);
/*!
* \since 1.8
* \brief Run a callback for potential matching destinations.
*
* \note
* See the explanation in ast_channel_tech::cc_callback for more
* details.
*
* \param inbound
* \param tech Channel technology to use
* \param dest Channel/group/peer or whatever the specific technology uses
* \param callback Function to call when a target is reached
* \retval 0 Always, I guess.
*/
int ast_cc_callback(struct ast_channel *inbound, const char * const tech, const char * const dest, ast_cc_callback_fn callback);
#endif /* _ASTERISK_CCSS_H */