mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
Rename everything Stasis-HTTP to ARI
This renames all files and API calls from several variants of Stasis-HTTP to ARI including: * Stasis-HTTP -> ARI * STASIS_HTTP -> ARI * stasis_http -> ari (ast_ari for global symbols, file names as well) * stasis http -> ARI Review: https://reviewboard.asterisk.org/r/2706/ (closes issue ASTERISK-22136) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395603 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
2969
res/ari/ari_model_validators.c
Normal file
2969
res/ari/ari_model_validators.c
Normal file
File diff suppressed because it is too large
Load Diff
962
res/ari/ari_model_validators.h
Normal file
962
res/ari/ari_model_validators.h
Normal file
@@ -0,0 +1,962 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* 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 Generated file - Build validators for ARI model objects.
|
||||
*
|
||||
* In addition to the normal validation functions one would normally expect,
|
||||
* each validator has a ast_ari_validate_{id}_fn() companion function that returns
|
||||
* the validator's function pointer.
|
||||
*
|
||||
* The reason for this seamingly useless indirection is the way function
|
||||
* pointers interfere with module loading. Asterisk attempts to dlopen() each
|
||||
* module using \c RTLD_LAZY in order to read some metadata from the module.
|
||||
* Unfortunately, if you take the address of a function, the function has to be
|
||||
* resolvable at load time, even if \c RTLD_LAZY is specified. By moving the
|
||||
* function-address-taking into this module, we can once again be lazy.
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_model_validators.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_ARI_MODEL_H
|
||||
#define _ASTERISK_ARI_MODEL_H
|
||||
|
||||
#include "asterisk/json.h"
|
||||
|
||||
/*! @{ */
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger void.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_void(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger byte.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_byte(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger boolean.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_boolean(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger int.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_int(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger long.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_long(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger float.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_float(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger double.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_double(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger string.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_string(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for native Swagger date.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_date(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for a Swagger List[]/JSON array.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \param fn Validator to call on every element in the array.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *));
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*!
|
||||
* \brief Function type for validator functions. Allows for
|
||||
*/
|
||||
typedef int (*ari_validator)(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Validator for AsteriskInfo.
|
||||
*
|
||||
* Asterisk system information
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_asterisk_info(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_asterisk_info().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_asterisk_info_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Variable.
|
||||
*
|
||||
* The value of a channel variable
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_variable(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_variable().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_variable_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Endpoint.
|
||||
*
|
||||
* An external device that may offer/accept calls to/from Asterisk.
|
||||
*
|
||||
* Unlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_endpoint(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_endpoint().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_endpoint_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for CallerID.
|
||||
*
|
||||
* Caller identification
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_caller_id(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_caller_id().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_caller_id_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Channel.
|
||||
*
|
||||
* A specific communication connection between Asterisk and an Endpoint.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Dialed.
|
||||
*
|
||||
* Dialed channel information.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_dialed(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_dialed().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_dialed_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for DialplanCEP.
|
||||
*
|
||||
* Dialplan location (context/extension/priority)
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_dialplan_cep(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_dialplan_cep().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_dialplan_cep_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Bridge.
|
||||
*
|
||||
* The merging of media from one or more channels.
|
||||
*
|
||||
* Everyone on the bridge receives the same audio.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_bridge(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_bridge().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_bridge_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for LiveRecording.
|
||||
*
|
||||
* A recording that is in progress
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_live_recording(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_live_recording().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_live_recording_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for StoredRecording.
|
||||
*
|
||||
* A past recording that may be played back.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_stored_recording(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_stored_recording().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_stored_recording_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for FormatLangPair.
|
||||
*
|
||||
* Identifies the format and language of a sound file
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_format_lang_pair(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_format_lang_pair().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_format_lang_pair_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Sound.
|
||||
*
|
||||
* A media file that may be played back.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_sound(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_sound().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_sound_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Playback.
|
||||
*
|
||||
* Object representing the playback of media to a channel
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_playback(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_playback().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_playback_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ApplicationReplaced.
|
||||
*
|
||||
* Notification that another WebSocket has taken over for an application.
|
||||
*
|
||||
* An application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_application_replaced(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_application_replaced().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_application_replaced_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for BridgeCreated.
|
||||
*
|
||||
* Notification that a bridge has been created.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_bridge_created(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_bridge_created().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_bridge_created_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for BridgeDestroyed.
|
||||
*
|
||||
* Notification that a bridge has been destroyed.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_bridge_destroyed(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_bridge_destroyed().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_bridge_destroyed_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for BridgeMerged.
|
||||
*
|
||||
* Notification that one bridge has merged into another.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_bridge_merged(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_bridge_merged().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_bridge_merged_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelCallerId.
|
||||
*
|
||||
* Channel changed Caller ID.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_caller_id(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_caller_id().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_caller_id_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelCreated.
|
||||
*
|
||||
* Notification that a channel has been created.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_created(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_created().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_created_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelDestroyed.
|
||||
*
|
||||
* Notification that a channel has been destroyed.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_destroyed(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_destroyed().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_destroyed_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelDialplan.
|
||||
*
|
||||
* Channel changed location in the dialplan.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_dialplan(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_dialplan().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_dialplan_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelDtmfReceived.
|
||||
*
|
||||
* DTMF received on a channel.
|
||||
*
|
||||
* This event is sent when the DTMF ends. There is no notification about the start of DTMF
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_dtmf_received(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_dtmf_received().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_dtmf_received_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelEnteredBridge.
|
||||
*
|
||||
* Notification that a channel has entered a bridge.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_entered_bridge(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_entered_bridge().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_entered_bridge_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelHangupRequest.
|
||||
*
|
||||
* A hangup was requested on the channel.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_hangup_request(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_hangup_request().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_hangup_request_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelLeftBridge.
|
||||
*
|
||||
* Notification that a channel has left a bridge.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_left_bridge(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_left_bridge().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_left_bridge_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelStateChange.
|
||||
*
|
||||
* Notification of a channel's state change.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_state_change(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_state_change().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_state_change_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelUserevent.
|
||||
*
|
||||
* User-generated event with additional user-defined fields in the object.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_userevent(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_userevent().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_userevent_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for ChannelVarset.
|
||||
*
|
||||
* Channel variable changed.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_channel_varset(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_channel_varset().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_channel_varset_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Event.
|
||||
*
|
||||
* Base type for asynchronous events from Asterisk.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_event(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_event().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_event_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for Message.
|
||||
*
|
||||
* Base type for errors and events
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_message(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_message().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_message_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for MissingParams.
|
||||
*
|
||||
* Error event sent when required params are missing.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_missing_params(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_missing_params().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_missing_params_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for PlaybackFinished.
|
||||
*
|
||||
* Event showing the completion of a media playback operation.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_playback_finished(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_playback_finished().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_playback_finished_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for PlaybackStarted.
|
||||
*
|
||||
* Event showing the start of a media playback operation.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_playback_started(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_playback_started().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_playback_started_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for StasisEnd.
|
||||
*
|
||||
* Notification that a channel has left a Stasis appliction.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_stasis_end(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_stasis_end().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_stasis_end_fn(void);
|
||||
|
||||
/*!
|
||||
* \brief Validator for StasisStart.
|
||||
*
|
||||
* Notification that a channel has entered a Stasis appliction.
|
||||
*
|
||||
* \param json JSON object to validate.
|
||||
* \returns True (non-zero) if valid.
|
||||
* \returns False (zero) if invalid.
|
||||
*/
|
||||
int ast_ari_validate_stasis_start(struct ast_json *json);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer to ast_ari_validate_stasis_start().
|
||||
*
|
||||
* See \ref ast_ari_model_validators.h for more details.
|
||||
*/
|
||||
ari_validator ast_ari_validate_stasis_start_fn(void);
|
||||
|
||||
/*
|
||||
* JSON models
|
||||
*
|
||||
* AsteriskInfo
|
||||
* Variable
|
||||
* - value: string (required)
|
||||
* Endpoint
|
||||
* - channel_ids: List[string] (required)
|
||||
* - resource: string (required)
|
||||
* - state: string
|
||||
* - technology: string (required)
|
||||
* CallerID
|
||||
* - name: string (required)
|
||||
* - number: string (required)
|
||||
* Channel
|
||||
* - accountcode: string (required)
|
||||
* - caller: CallerID (required)
|
||||
* - connected: CallerID (required)
|
||||
* - creationtime: Date (required)
|
||||
* - dialplan: DialplanCEP (required)
|
||||
* - id: string (required)
|
||||
* - name: string (required)
|
||||
* - state: string (required)
|
||||
* Dialed
|
||||
* DialplanCEP
|
||||
* - context: string (required)
|
||||
* - exten: string (required)
|
||||
* - priority: long (required)
|
||||
* Bridge
|
||||
* - bridge_class: string (required)
|
||||
* - bridge_type: string (required)
|
||||
* - channels: List[string] (required)
|
||||
* - id: string (required)
|
||||
* - technology: string (required)
|
||||
* LiveRecording
|
||||
* - format: string (required)
|
||||
* - name: string (required)
|
||||
* - state: string (required)
|
||||
* StoredRecording
|
||||
* - duration_seconds: int
|
||||
* - formats: List[string] (required)
|
||||
* - id: string (required)
|
||||
* - time: Date
|
||||
* FormatLangPair
|
||||
* - format: string (required)
|
||||
* - language: string (required)
|
||||
* Sound
|
||||
* - formats: List[FormatLangPair] (required)
|
||||
* - id: string (required)
|
||||
* - text: string
|
||||
* Playback
|
||||
* - id: string (required)
|
||||
* - language: string
|
||||
* - media_uri: string (required)
|
||||
* - state: string (required)
|
||||
* - target_uri: string (required)
|
||||
* ApplicationReplaced
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* BridgeCreated
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - bridge: Bridge (required)
|
||||
* BridgeDestroyed
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - bridge: Bridge (required)
|
||||
* BridgeMerged
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - bridge: Bridge (required)
|
||||
* - bridge_from: Bridge (required)
|
||||
* ChannelCallerId
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - caller_presentation: int (required)
|
||||
* - caller_presentation_txt: string (required)
|
||||
* - channel: Channel (required)
|
||||
* ChannelCreated
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel (required)
|
||||
* ChannelDestroyed
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - cause: int (required)
|
||||
* - cause_txt: string (required)
|
||||
* - channel: Channel (required)
|
||||
* ChannelDialplan
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel (required)
|
||||
* - dialplan_app: string (required)
|
||||
* - dialplan_app_data: string (required)
|
||||
* ChannelDtmfReceived
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel (required)
|
||||
* - digit: string (required)
|
||||
* - duration_ms: int (required)
|
||||
* ChannelEnteredBridge
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - bridge: Bridge (required)
|
||||
* - channel: Channel
|
||||
* ChannelHangupRequest
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - cause: int
|
||||
* - channel: Channel (required)
|
||||
* - soft: boolean
|
||||
* ChannelLeftBridge
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - bridge: Bridge (required)
|
||||
* - channel: Channel (required)
|
||||
* ChannelStateChange
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel (required)
|
||||
* ChannelUserevent
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel (required)
|
||||
* - eventname: string (required)
|
||||
* ChannelVarset
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel
|
||||
* - value: string (required)
|
||||
* - variable: string (required)
|
||||
* Event
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* Message
|
||||
* - type: string (required)
|
||||
* MissingParams
|
||||
* - type: string (required)
|
||||
* - params: List[string] (required)
|
||||
* PlaybackFinished
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - playback: Playback (required)
|
||||
* PlaybackStarted
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - playback: Playback (required)
|
||||
* StasisEnd
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - channel: Channel (required)
|
||||
* StasisStart
|
||||
* - type: string (required)
|
||||
* - application: string (required)
|
||||
* - timestamp: Date
|
||||
* - args: List[string] (required)
|
||||
* - channel: Channel (required)
|
||||
*/
|
||||
|
||||
#endif /* _ASTERISK_ARI_MODEL_H */
|
165
res/ari/ari_websockets.c
Normal file
165
res/ari/ari_websockets.c
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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.
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief WebSocket support for RESTful API's.
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
struct ast_ari_websocket_session {
|
||||
struct ast_websocket *ws_session;
|
||||
int (*validator)(struct ast_json *);
|
||||
};
|
||||
|
||||
static void websocket_session_dtor(void *obj)
|
||||
{
|
||||
struct ast_ari_websocket_session *session = obj;
|
||||
|
||||
ast_websocket_unref(session->ws_session);
|
||||
session->ws_session = NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Validator that always succeeds.
|
||||
*/
|
||||
static int null_validator(struct ast_json *json)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ast_ari_websocket_session *ast_ari_websocket_session_create(
|
||||
struct ast_websocket *ws_session, int (*validator)(struct ast_json *))
|
||||
{
|
||||
RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
|
||||
|
||||
if (ws_session == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (validator == NULL) {
|
||||
validator = null_validator;
|
||||
}
|
||||
|
||||
if (ast_websocket_set_nonblock(ws_session) != 0) {
|
||||
ast_log(LOG_ERROR,
|
||||
"ARI web socket failed to set nonblock; closing: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
session = ao2_alloc(sizeof(*session), websocket_session_dtor);
|
||||
if (!session) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(ws_session, +1);
|
||||
session->ws_session = ws_session;
|
||||
session->validator = validator;
|
||||
|
||||
ao2_ref(session, +1);
|
||||
return session;
|
||||
}
|
||||
|
||||
struct ast_json *ast_ari_websocket_session_read(
|
||||
struct ast_ari_websocket_session *session)
|
||||
{
|
||||
RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
|
||||
|
||||
while (!message) {
|
||||
int res;
|
||||
char *payload;
|
||||
uint64_t payload_len;
|
||||
enum ast_websocket_opcode opcode;
|
||||
int fragmented;
|
||||
|
||||
res = ast_wait_for_input(
|
||||
ast_websocket_fd(session->ws_session), -1);
|
||||
|
||||
if (res <= 0) {
|
||||
ast_log(LOG_WARNING, "WebSocket poll error: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = ast_websocket_read(session->ws_session, &payload,
|
||||
&payload_len, &opcode, &fragmented);
|
||||
|
||||
if (res != 0) {
|
||||
ast_log(LOG_WARNING, "WebSocket read error: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case AST_WEBSOCKET_OPCODE_CLOSE:
|
||||
ast_debug(1, "WebSocket closed by peer\n");
|
||||
return NULL;
|
||||
case AST_WEBSOCKET_OPCODE_TEXT:
|
||||
message = ast_json_load_buf(payload, payload_len, NULL);
|
||||
if (message == NULL) {
|
||||
ast_log(LOG_WARNING,
|
||||
"WebSocket input failed to parse\n");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Ignore all other message types */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ast_json_ref(message);
|
||||
}
|
||||
|
||||
#define VALIDATION_FAILED \
|
||||
"{" \
|
||||
" \"error\": \"InvalidMessage\"," \
|
||||
" \"message\": \"Message validation failed\"" \
|
||||
"}"
|
||||
|
||||
int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
|
||||
struct ast_json *message)
|
||||
{
|
||||
RAII_VAR(char *, str, NULL, ast_free);
|
||||
|
||||
#ifdef AST_DEVMODE
|
||||
if (!session->validator(message)) {
|
||||
ast_log(LOG_ERROR, "Outgoing message failed validation\n");
|
||||
return ast_websocket_write(session->ws_session,
|
||||
AST_WEBSOCKET_OPCODE_TEXT, VALIDATION_FAILED,
|
||||
strlen(VALIDATION_FAILED));
|
||||
}
|
||||
#endif
|
||||
|
||||
str = ast_json_dump_string_format(message, ast_ari_json_format());
|
||||
|
||||
if (str == NULL) {
|
||||
ast_log(LOG_ERROR, "Failed to encode JSON object\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ast_websocket_write(session->ws_session,
|
||||
AST_WEBSOCKET_OPCODE_TEXT, str, strlen(str));
|
||||
}
|
267
res/ari/cli.c
Normal file
267
res/ari/cli.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Command line for ARI.
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/cli.h"
|
||||
#include "internal.h"
|
||||
|
||||
static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "ari show status";
|
||||
e->usage =
|
||||
"Usage: ari show status\n"
|
||||
" Shows all ARI settings\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (a->argc != 3) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
conf = ast_ari_config_get();
|
||||
|
||||
if (!conf) {
|
||||
ast_cli(a->fd, "Error getting ARI configuration\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "ARI Status:\n");
|
||||
ast_cli(a->fd, "Enabled: %s\n", AST_CLI_YESNO(conf->general->enabled));
|
||||
ast_cli(a->fd, "Output format: ");
|
||||
switch (conf->general->format) {
|
||||
case AST_JSON_COMPACT:
|
||||
ast_cli(a->fd, "compact");
|
||||
break;
|
||||
case AST_JSON_PRETTY:
|
||||
ast_cli(a->fd, "pretty");
|
||||
break;
|
||||
}
|
||||
ast_cli(a->fd, "\n");
|
||||
ast_cli(a->fd, "Auth realm: %s\n", conf->general->auth_realm);
|
||||
ast_cli(a->fd, "Allowed Origins: %s\n", conf->general->allowed_origins);
|
||||
ast_cli(a->fd, "User count: %d\n", ao2_container_count(conf->users));
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static int show_users_cb(void *obj, void *arg, int flags)
|
||||
{
|
||||
struct ast_ari_conf_user *user = obj;
|
||||
struct ast_cli_args *a = arg;
|
||||
|
||||
ast_cli(a->fd, "%-4s %s\n",
|
||||
AST_CLI_YESNO(user->read_only),
|
||||
user->username);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *ari_show_users(struct ast_cli_entry *e, int cmd,
|
||||
struct ast_cli_args *a)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "ari show users";
|
||||
e->usage =
|
||||
"Usage: ari show users\n"
|
||||
" Shows all ARI users\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (a->argc != 3) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
conf = ast_ari_config_get();
|
||||
if (!conf) {
|
||||
ast_cli(a->fd, "Error getting ARI configuration\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "r/o? Username\n");
|
||||
ast_cli(a->fd, "---- --------\n");
|
||||
|
||||
ao2_callback(conf->users, OBJ_NODATA, show_users_cb, a);
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
struct user_complete {
|
||||
/*! Nth user to search for */
|
||||
int state;
|
||||
/*! Which user currently on */
|
||||
int which;
|
||||
};
|
||||
|
||||
static int complete_ari_user_search(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
struct user_complete *search = data;
|
||||
|
||||
if (++search->which > search->state) {
|
||||
return CMP_MATCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *complete_ari_user(struct ast_cli_args *a)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
|
||||
|
||||
struct user_complete search = {
|
||||
.state = a->n,
|
||||
};
|
||||
|
||||
conf = ast_ari_config_get();
|
||||
if (!conf) {
|
||||
ast_cli(a->fd, "Error getting ARI configuration\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
user = ao2_callback_data(conf->users,
|
||||
ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
|
||||
complete_ari_user_search, (char*)a->word, &search);
|
||||
|
||||
return user ? ast_strdup(user->username) : NULL;
|
||||
}
|
||||
|
||||
static char *complete_ari_show_user(struct ast_cli_args *a)
|
||||
{
|
||||
if (a->pos == 3) {
|
||||
return complete_ari_user(a);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *ari_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "ari show user";
|
||||
e->usage =
|
||||
"Usage: ari show user <username>\n"
|
||||
" Shows a specific ARI user\n";
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return complete_ari_show_user(a);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (a->argc != 4) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
conf = ast_ari_config_get();
|
||||
|
||||
if (!conf) {
|
||||
ast_cli(a->fd, "Error getting ARI configuration\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
user = ao2_find(conf->users, a->argv[3], OBJ_KEY);
|
||||
if (!user) {
|
||||
ast_cli(a->fd, "User '%s' not found\n", a->argv[3]);
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
ast_cli(a->fd, "Username: %s\n", user->username);
|
||||
ast_cli(a->fd, "Read only?: %s\n", AST_CLI_YESNO(user->read_only));
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static char *ari_mkpasswd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
||||
{
|
||||
RAII_VAR(char *, crypted, NULL, ast_free);
|
||||
|
||||
switch (cmd) {
|
||||
case CLI_INIT:
|
||||
e->command = "ari mkpasswd";
|
||||
e->usage =
|
||||
"Usage: ari mkpasswd <password>\n"
|
||||
" Encrypts a password for use in ari.conf\n"
|
||||
" Be aware that the password will be shown in the\n"
|
||||
" command line history. The mkpasswd shell command\n"
|
||||
" may be preferable.\n"
|
||||
;
|
||||
return NULL;
|
||||
case CLI_GENERATE:
|
||||
return NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (a->argc != 3) {
|
||||
return CLI_SHOWUSAGE;
|
||||
}
|
||||
|
||||
crypted = ast_crypt_encrypt(a->argv[2]);
|
||||
if (!crypted) {
|
||||
ast_cli(a->fd, "Failed to encrypt password\n");
|
||||
return CLI_FAILURE;
|
||||
}
|
||||
|
||||
ast_cli(a->fd,
|
||||
"; Copy the following two lines into ari.conf\n");
|
||||
ast_cli(a->fd, "password_format = crypt\n");
|
||||
ast_cli(a->fd, "password = %s\n", crypted);
|
||||
|
||||
return CLI_SUCCESS;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry cli_ari[] = {
|
||||
AST_CLI_DEFINE(ari_show, "Show ARI settings"),
|
||||
AST_CLI_DEFINE(ari_show_users, "List ARI users"),
|
||||
AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
|
||||
AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"),
|
||||
};
|
||||
|
||||
int ast_ari_cli_register(void) {
|
||||
return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
|
||||
}
|
||||
|
||||
void ast_ari_cli_unregister(void) {
|
||||
ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
|
||||
}
|
345
res/ari/config.c
Normal file
345
res/ari/config.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Config framework stuffz for ARI.
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/config_options.h"
|
||||
#include "internal.h"
|
||||
|
||||
/*! \brief Locking container for safe configuration access. */
|
||||
static AO2_GLOBAL_OBJ_STATIC(confs);
|
||||
|
||||
/*! \brief Mapping of the ARI conf struct's globals to the
|
||||
* general context in the config file. */
|
||||
static struct aco_type general_option = {
|
||||
.type = ACO_GLOBAL,
|
||||
.name = "general",
|
||||
.item_offset = offsetof(struct ast_ari_conf, general),
|
||||
.category = "^general$",
|
||||
.category_match = ACO_WHITELIST,
|
||||
};
|
||||
|
||||
static struct aco_type *general_options[] = ACO_TYPES(&general_option);
|
||||
|
||||
/*! \brief Encoding format handler converts from boolean to enum. */
|
||||
static int encoding_format_handler(const struct aco_option *opt,
|
||||
struct ast_variable *var, void *obj)
|
||||
{
|
||||
struct ast_ari_conf_general *general = obj;
|
||||
|
||||
if (!strcasecmp(var->name, "pretty")) {
|
||||
general->format = ast_true(var->value) ?
|
||||
AST_JSON_PRETTY : AST_JSON_COMPACT;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Parses the ast_ari_password_format enum from a config file */
|
||||
static int password_format_handler(const struct aco_option *opt,
|
||||
struct ast_variable *var, void *obj)
|
||||
{
|
||||
struct ast_ari_conf_user *user = obj;
|
||||
|
||||
if (strcasecmp(var->value, "plain") == 0) {
|
||||
user->password_format = ARI_PASSWORD_FORMAT_PLAIN;
|
||||
} else if (strcasecmp(var->value, "crypt") == 0) {
|
||||
user->password_format = ARI_PASSWORD_FORMAT_CRYPT;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Destructor for \ref ast_ari_conf_user */
|
||||
static void user_dtor(void *obj)
|
||||
{
|
||||
struct ast_ari_conf_user *user = obj;
|
||||
ast_debug(3, "Disposing of user %s\n", user->username);
|
||||
ast_free(user->username);
|
||||
}
|
||||
|
||||
/*! \brief Allocate an \ref ast_ari_conf_user for config parsing */
|
||||
static void *user_alloc(const char *cat)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
|
||||
|
||||
if (!cat) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_debug(3, "Allocating user %s\n", cat);
|
||||
|
||||
user = ao2_alloc_options(sizeof(*user), user_dtor,
|
||||
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
||||
if (!user) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
user->username = ast_strdup(cat);
|
||||
if (!user->username) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(user, +1);
|
||||
return user;
|
||||
}
|
||||
|
||||
/*! \brief Sorting function for use with red/black tree */
|
||||
static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
|
||||
{
|
||||
const struct ast_ari_conf_user *user_left = obj_left;
|
||||
|
||||
if (flags & OBJ_PARTIAL_KEY) {
|
||||
const char *key_right = obj_right;
|
||||
return strncasecmp(user_left->username, key_right,
|
||||
strlen(key_right));
|
||||
} else if (flags & OBJ_KEY) {
|
||||
const char *key_right = obj_right;
|
||||
return strcasecmp(user_left->username, key_right);
|
||||
} else {
|
||||
const struct ast_ari_conf_user *user_right = obj_right;
|
||||
const char *key_right = user_right->username;
|
||||
return strcasecmp(user_left->username, key_right);
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief \ref aco_type item_find function */
|
||||
static void *user_find(struct ao2_container *tmp_container, const char *cat)
|
||||
{
|
||||
if (!cat) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ao2_find(tmp_container, cat, OBJ_KEY);
|
||||
}
|
||||
|
||||
static struct aco_type user_option = {
|
||||
.type = ACO_ITEM,
|
||||
.name = "user",
|
||||
.category_match = ACO_BLACKLIST,
|
||||
.category = "^general$",
|
||||
.matchfield = "type",
|
||||
.matchvalue = "user",
|
||||
.item_alloc = user_alloc,
|
||||
.item_find = user_find,
|
||||
.item_offset = offsetof(struct ast_ari_conf, users),
|
||||
};
|
||||
|
||||
static struct aco_type *user[] = ACO_TYPES(&user_option);
|
||||
|
||||
/*! \brief \ref ast_ari_conf destructor. */
|
||||
static void conf_destructor(void *obj)
|
||||
{
|
||||
struct ast_ari_conf *cfg = obj;
|
||||
|
||||
ast_string_field_free_memory(cfg->general);
|
||||
|
||||
ao2_cleanup(cfg->general);
|
||||
ao2_cleanup(cfg->users);
|
||||
}
|
||||
|
||||
/*! \brief Allocate an \ref ast_ari_conf for config parsing */
|
||||
static void *conf_alloc(void)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, cfg, NULL, ao2_cleanup);
|
||||
|
||||
cfg = ao2_alloc_options(sizeof(*cfg), conf_destructor,
|
||||
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
||||
if (!cfg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cfg->general = ao2_alloc_options(sizeof(*cfg->general), NULL,
|
||||
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
||||
if (!cfg->general) {
|
||||
return NULL;
|
||||
}
|
||||
aco_set_defaults(&general_option, "general", cfg->general);
|
||||
|
||||
if (ast_string_field_init(cfg->general, 64)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cfg->users = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
|
||||
AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, user_sort_cmp, NULL);
|
||||
|
||||
ao2_ref(cfg, +1);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
#define CONF_FILENAME "ari.conf"
|
||||
|
||||
/*! \brief The conf file that's processed for the module. */
|
||||
static struct aco_file conf_file = {
|
||||
/*! The config file name. */
|
||||
.filename = CONF_FILENAME,
|
||||
/*! The mapping object types to be processed. */
|
||||
.types = ACO_TYPES(&general_option, &user_option),
|
||||
};
|
||||
|
||||
CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
|
||||
.files = ACO_FILES(&conf_file));
|
||||
|
||||
struct ast_ari_conf *ast_ari_config_get(void)
|
||||
{
|
||||
struct ast_ari_conf *res = ao2_global_obj_ref(confs);
|
||||
if (!res) {
|
||||
ast_log(LOG_ERROR,
|
||||
"Error obtaining config from " CONF_FILENAME "\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_ari_conf_user *ast_ari_config_validate_user(const char *username,
|
||||
const char *password)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
|
||||
int is_valid = 0;
|
||||
|
||||
conf = ast_ari_config_get();
|
||||
if (!conf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
user = ao2_find(conf->users, username, OBJ_KEY);
|
||||
if (!user) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(user->password)) {
|
||||
ast_log(LOG_WARNING,
|
||||
"User '%s' missing password; authentication failed\n",
|
||||
user->username);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (user->password_format) {
|
||||
case ARI_PASSWORD_FORMAT_PLAIN:
|
||||
is_valid = strcmp(password, user->password) == 0;
|
||||
break;
|
||||
case ARI_PASSWORD_FORMAT_CRYPT:
|
||||
is_valid = ast_crypt_validate(password, user->password);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_valid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(user, +1);
|
||||
return user;
|
||||
}
|
||||
|
||||
/*! \brief Callback to validate a user object */
|
||||
static int validate_user_cb(void *obj, void *arg, int flags)
|
||||
{
|
||||
struct ast_ari_conf_user *user = obj;
|
||||
|
||||
if (ast_strlen_zero(user->password)) {
|
||||
ast_log(LOG_WARNING, "User '%s' missing password\n",
|
||||
user->username);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Load (or reload) configuration. */
|
||||
static int process_config(int reload)
|
||||
{
|
||||
RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
|
||||
|
||||
switch (aco_process_config(&cfg_info, reload)) {
|
||||
case ACO_PROCESS_ERROR:
|
||||
return -1;
|
||||
case ACO_PROCESS_OK:
|
||||
case ACO_PROCESS_UNCHANGED:
|
||||
break;
|
||||
}
|
||||
|
||||
conf = ast_ari_config_get();
|
||||
if (!conf) {
|
||||
ast_assert(0); /* We just configured; it should be there */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ao2_container_count(conf->users) == 0) {
|
||||
ast_log(LOG_ERROR, "No configured users for ARI\n");
|
||||
}
|
||||
|
||||
ao2_callback(conf->users, OBJ_NODATA, validate_user_cb, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_ari_config_init(void)
|
||||
{
|
||||
if (aco_info_init(&cfg_info)) {
|
||||
aco_info_destroy(&cfg_info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
aco_option_register(&cfg_info, "enabled", ACO_EXACT, general_options,
|
||||
"yes", OPT_BOOL_T, 1,
|
||||
FLDSET(struct ast_ari_conf_general, enabled));
|
||||
aco_option_register_custom(&cfg_info, "pretty", ACO_EXACT,
|
||||
general_options, "no", encoding_format_handler, 0);
|
||||
aco_option_register(&cfg_info, "auth_realm", ACO_EXACT, general_options,
|
||||
"Asterisk REST Interface", OPT_CHAR_ARRAY_T, 0,
|
||||
FLDSET(struct ast_ari_conf_general, auth_realm),
|
||||
ARI_AUTH_REALM_LEN);
|
||||
aco_option_register(&cfg_info, "allowed_origins", ACO_EXACT, general_options,
|
||||
"", OPT_STRINGFIELD_T, 0,
|
||||
STRFLDSET(struct ast_ari_conf_general, allowed_origins));
|
||||
|
||||
aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
|
||||
OPT_NOOP_T, 0, 0);
|
||||
aco_option_register(&cfg_info, "read_only", ACO_EXACT, user,
|
||||
"no", OPT_BOOL_T, 1,
|
||||
FLDSET(struct ast_ari_conf_user, read_only));
|
||||
aco_option_register(&cfg_info, "password", ACO_EXACT, user,
|
||||
"", OPT_CHAR_ARRAY_T, 0,
|
||||
FLDSET(struct ast_ari_conf_user, password), ARI_PASSWORD_LEN);
|
||||
aco_option_register_custom(&cfg_info, "password_format", ACO_EXACT,
|
||||
user, "plain", password_format_handler, 0);
|
||||
|
||||
return process_config(0);
|
||||
}
|
||||
|
||||
int ast_ari_config_reload(void)
|
||||
{
|
||||
return process_config(1);
|
||||
}
|
||||
|
||||
void ast_ari_config_destroy(void)
|
||||
{
|
||||
aco_info_destroy(&cfg_info);
|
||||
ao2_global_obj_release(confs);
|
||||
}
|
143
res/ari/internal.h
Normal file
143
res/ari/internal.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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.
|
||||
*/
|
||||
|
||||
#ifndef ARI_INTERNAL_H_
|
||||
#define ARI_INTERNAL_H_
|
||||
|
||||
/*! \file
|
||||
*
|
||||
* \brief Internal API's for res_ari.
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk/json.h"
|
||||
|
||||
/*! @{ */
|
||||
|
||||
/*!
|
||||
* \brief Register CLI commands for ARI.
|
||||
*
|
||||
* \return 0 on success.
|
||||
* \return Non-zero on error.
|
||||
*/
|
||||
int ast_ari_cli_register(void);
|
||||
|
||||
/*!
|
||||
* \brief Unregister CLI commands for ARI.
|
||||
*/
|
||||
void ast_ari_cli_unregister(void);
|
||||
|
||||
/*! @} */
|
||||
|
||||
/*! @{ */
|
||||
|
||||
struct ast_ari_conf_general;
|
||||
|
||||
/*! \brief All configuration options for ARI. */
|
||||
struct ast_ari_conf {
|
||||
/*! The general section configuration options. */
|
||||
struct ast_ari_conf_general *general;
|
||||
/*! Configured users */
|
||||
struct ao2_container *users;
|
||||
};
|
||||
|
||||
/*! Max length for auth_realm field */
|
||||
#define ARI_AUTH_REALM_LEN 80
|
||||
|
||||
/*! \brief Global configuration options for ARI. */
|
||||
struct ast_ari_conf_general {
|
||||
/*! Enabled by default, disabled if false. */
|
||||
int enabled;
|
||||
/*! Encoding format used during output (default compact). */
|
||||
enum ast_json_encoding_format format;
|
||||
/*! Authentication realm */
|
||||
char auth_realm[ARI_AUTH_REALM_LEN];
|
||||
|
||||
AST_DECLARE_STRING_FIELDS(
|
||||
AST_STRING_FIELD(allowed_origins);
|
||||
);
|
||||
};
|
||||
|
||||
/*! \brief Password format */
|
||||
enum ast_ari_password_format {
|
||||
/*! \brief Plaintext password */
|
||||
ARI_PASSWORD_FORMAT_PLAIN,
|
||||
/*! crypt(3) password */
|
||||
ARI_PASSWORD_FORMAT_CRYPT,
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief User's password mx length.
|
||||
*
|
||||
* If 256 seems like a lot, a crypt SHA-512 has over 106 characters.
|
||||
*/
|
||||
#define ARI_PASSWORD_LEN 256
|
||||
|
||||
/*! \brief Per-user configuration options */
|
||||
struct ast_ari_conf_user {
|
||||
/*! Username for authentication */
|
||||
char *username;
|
||||
/*! User's password. */
|
||||
char password[ARI_PASSWORD_LEN];
|
||||
/*! Format for the password field */
|
||||
enum ast_ari_password_format password_format;
|
||||
/*! If true, user cannot execute change operations */
|
||||
int read_only;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Initialize the ARI configuration
|
||||
*/
|
||||
int ast_ari_config_init(void);
|
||||
|
||||
/*!
|
||||
* \brief Reload the ARI configuration
|
||||
*/
|
||||
int ast_ari_config_reload(void);
|
||||
|
||||
/*!
|
||||
* \brief Destroy the ARI configuration
|
||||
*/
|
||||
void ast_ari_config_destroy(void);
|
||||
|
||||
/*!
|
||||
* \brief Get the current ARI configuration.
|
||||
*
|
||||
* This is an immutable object, so don't modify it. It is AO2 managed, so
|
||||
* ao2_cleanup() when you're done with it.
|
||||
*
|
||||
* \return ARI configuration object.
|
||||
* \return \c NULL on error.
|
||||
*/
|
||||
struct ast_ari_conf *ast_ari_config_get(void);
|
||||
|
||||
/*!
|
||||
* \brief Validated a user's credentials.
|
||||
*
|
||||
* \param username Name of the user.
|
||||
* \param password User's password.
|
||||
* \return User object.
|
||||
* \return \c NULL if username or password is invalid.
|
||||
*/
|
||||
struct ast_ari_conf_user *ast_ari_config_validate_user(const char *username,
|
||||
const char *password);
|
||||
|
||||
/*! @} */
|
||||
|
||||
|
||||
#endif /* ARI_INTERNAL_H_ */
|
80
res/ari/resource_asterisk.c
Normal file
80
res/ari/resource_asterisk.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/* -*- C -*-
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Implementation for ARI stubs.
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "resource_asterisk.h"
|
||||
#include "asterisk/pbx.h"
|
||||
|
||||
void ast_ari_get_asterisk_info(struct ast_variable *headers, struct ast_get_asterisk_info_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ari_get_asterisk_info\n");
|
||||
}
|
||||
|
||||
void ast_ari_get_global_var(struct ast_variable *headers, struct ast_get_global_var_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
RAII_VAR(struct ast_str *, tmp, ast_str_create(32), ast_free);
|
||||
|
||||
const char *value;
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
if (!tmp) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
value = ast_str_retrieve_variable(&tmp, 0, NULL, NULL, args->variable);
|
||||
|
||||
if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
|
||||
void ast_ari_set_global_var(struct ast_variable *headers, struct ast_set_global_var_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_assert(response != NULL);
|
||||
|
||||
if (ast_strlen_zero(args->variable)) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Variable name is required");
|
||||
return;
|
||||
}
|
||||
|
||||
pbx_builtin_setvar_helper(NULL, args->variable, args->value);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
84
res/ari/resource_asterisk.h
Normal file
84
res/ari/resource_asterisk.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_asterisk.c
|
||||
*
|
||||
* Asterisk resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_ASTERISK_H
|
||||
#define _ASTERISK_RESOURCE_ASTERISK_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_asterisk_info() */
|
||||
struct ast_get_asterisk_info_args {
|
||||
/*! \brief Filter information returned */
|
||||
const char *only;
|
||||
};
|
||||
/*!
|
||||
* \brief Gets Asterisk system information.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_asterisk_info(struct ast_variable *headers, struct ast_get_asterisk_info_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_global_var() */
|
||||
struct ast_get_global_var_args {
|
||||
/*! \brief The variable to get */
|
||||
const char *variable;
|
||||
};
|
||||
/*!
|
||||
* \brief Get the value of a global variable.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_global_var(struct ast_variable *headers, struct ast_get_global_var_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_set_global_var() */
|
||||
struct ast_set_global_var_args {
|
||||
/*! \brief The variable to set */
|
||||
const char *variable;
|
||||
/*! \brief The value to set the variable to */
|
||||
const char *value;
|
||||
};
|
||||
/*!
|
||||
* \brief Set the value of a global variable.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_set_global_var(struct ast_variable *headers, struct ast_set_global_var_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_ASTERISK_H */
|
514
res/ari/resource_bridges.c
Normal file
514
res/ari/resource_bridges.c
Normal file
@@ -0,0 +1,514 @@
|
||||
/* -*- C -*-
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Implementation for ARI stubs.
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "resource_bridges.h"
|
||||
#include "asterisk/stasis.h"
|
||||
#include "asterisk/stasis_bridges.h"
|
||||
#include "asterisk/stasis_app.h"
|
||||
#include "asterisk/stasis_app_playback.h"
|
||||
#include "asterisk/stasis_app_recording.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "asterisk/core_unreal.h"
|
||||
#include "asterisk/channel.h"
|
||||
#include "asterisk/bridge.h"
|
||||
#include "asterisk/format_cap.h"
|
||||
#include "asterisk/file.h"
|
||||
|
||||
/*!
|
||||
* \brief Finds a bridge, filling the response with an error, if appropriate.
|
||||
*
|
||||
* \param[out] response Response to fill with an error if control is not found.
|
||||
* \param bridge_id ID of the bridge to lookup.
|
||||
*
|
||||
* \return Bridget.
|
||||
* \return \c NULL if bridge does not exist.
|
||||
*/
|
||||
static struct ast_bridge *find_bridge(
|
||||
struct ast_ari_response *response,
|
||||
const char *bridge_id)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
bridge = stasis_app_bridge_find_by_id(bridge_id);
|
||||
if (bridge == NULL) {
|
||||
RAII_VAR(struct ast_bridge_snapshot *, snapshot,
|
||||
ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
|
||||
if (!snapshot) {
|
||||
ast_ari_response_error(response, 404, "Not found",
|
||||
"Bridge not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_ari_response_error(response, 409, "Conflict",
|
||||
"Bridge not in Stasis application");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(bridge, +1);
|
||||
return bridge;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Finds the control object for a channel, filling the response with an
|
||||
* error, if appropriate.
|
||||
* \param[out] response Response to fill with an error if control is not found.
|
||||
* \param channel_id ID of the channel to lookup.
|
||||
* \return Channel control object.
|
||||
* \return \c NULL if control object does not exist.
|
||||
*/
|
||||
static struct stasis_app_control *find_channel_control(
|
||||
struct ast_ari_response *response,
|
||||
const char *channel_id)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
control = stasis_app_control_find_by_channel_id(channel_id);
|
||||
if (control == NULL) {
|
||||
ast_ari_response_error(response, 422, "Unprocessable Entity",
|
||||
"Channel not in Stasis application");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(control, +1);
|
||||
return control;
|
||||
}
|
||||
|
||||
void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
if (!bridge) {
|
||||
return;
|
||||
}
|
||||
|
||||
control = find_channel_control(response, args->channel);
|
||||
if (!control) {
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_add_channel_to_bridge(control, bridge);
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
if (!bridge) {
|
||||
return;
|
||||
}
|
||||
|
||||
control = find_channel_control(response, args->channel);
|
||||
if (!control) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* BUGBUG this should make sure the bridge requested for removal is actually
|
||||
* the bridge the channel is in. This will be possible once the bridge uniqueid
|
||||
* is added to the channel snapshot. A 409 response should be issued if the bridge
|
||||
* uniqueids don't match */
|
||||
if (stasis_app_control_remove_channel_from_bridge(control, bridge)) {
|
||||
ast_ari_response_error(response, 500, "Internal Error",
|
||||
"Could not remove channel from bridge");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
struct bridge_channel_control_thread_data {
|
||||
struct ast_channel *bridge_channel;
|
||||
struct stasis_app_control *control;
|
||||
};
|
||||
|
||||
static void *bridge_channel_control_thread(void *data)
|
||||
{
|
||||
struct bridge_channel_control_thread_data *thread_data = data;
|
||||
struct ast_channel *bridge_channel = thread_data->bridge_channel;
|
||||
struct stasis_app_control *control = thread_data->control;
|
||||
|
||||
RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
|
||||
|
||||
if (callid) {
|
||||
ast_callid_threadassoc_add(callid);
|
||||
}
|
||||
|
||||
ast_free(thread_data);
|
||||
thread_data = NULL;
|
||||
|
||||
stasis_app_control_execute_until_exhausted(bridge_channel, control);
|
||||
|
||||
ast_hangup(bridge_channel);
|
||||
ao2_cleanup(control);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ast_channel *prepare_bridge_media_channel(const char *type)
|
||||
{
|
||||
RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
|
||||
struct ast_format format;
|
||||
|
||||
cap = ast_format_cap_alloc_nolock();
|
||||
if (!cap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
|
||||
|
||||
if (!cap) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ast_request(type, cap, NULL, "ARI", NULL);
|
||||
}
|
||||
|
||||
void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
|
||||
RAII_VAR(char *, playback_url, NULL, ast_free);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
|
||||
struct bridge_channel_control_thread_data *thread_data;
|
||||
const char *language;
|
||||
pthread_t threadid;
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
if (!bridge) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error", "Could not create playback channel");
|
||||
return;
|
||||
}
|
||||
ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
|
||||
|
||||
if (ast_unreal_channel_push_to_bridge(play_channel, bridge)) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error", "Failed to put playback channel into the bridge");
|
||||
return;
|
||||
}
|
||||
|
||||
control = stasis_app_control_create(play_channel);
|
||||
if (control == NULL) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot = stasis_app_control_get_snapshot(control);
|
||||
if (!snapshot) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error", "Failed to get control snapshot");
|
||||
return;
|
||||
}
|
||||
|
||||
language = S_OR(args->lang, snapshot->language);
|
||||
|
||||
playback = stasis_app_control_play_uri(control, args->media, language,
|
||||
args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
|
||||
args->offsetms);
|
||||
|
||||
if (!playback) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_asprintf(&playback_url, "/playback/%s",
|
||||
stasis_app_playback_get_id(playback));
|
||||
|
||||
if (!playback_url) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
json = stasis_app_playback_to_json(playback);
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Give play_channel and control reference to the thread data */
|
||||
thread_data = ast_calloc(1, sizeof(*thread_data));
|
||||
if (!thread_data) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_data->bridge_channel = play_channel;
|
||||
thread_data->control = control;
|
||||
|
||||
if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
ast_free(thread_data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
|
||||
play_channel = NULL;
|
||||
control = NULL;
|
||||
|
||||
ast_ari_response_created(response, playback_url, json);
|
||||
}
|
||||
|
||||
void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
|
||||
RAII_VAR(char *, recording_url, NULL, ast_free);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
|
||||
RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
|
||||
|
||||
size_t uri_name_maxlen;
|
||||
struct bridge_channel_control_thread_data *thread_data;
|
||||
pthread_t threadid;
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
if (bridge == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error", "Failed to create recording channel");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ast_unreal_channel_push_to_bridge(record_channel, bridge)) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error", "Failed to put recording channel into the bridge");
|
||||
return;
|
||||
}
|
||||
|
||||
control = stasis_app_control_create(record_channel);
|
||||
if (control == NULL) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
options = stasis_app_recording_options_create(args->name, args->format);
|
||||
if (options == NULL) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
options->max_silence_seconds = args->max_silence_seconds;
|
||||
options->max_duration_seconds = args->max_duration_seconds;
|
||||
options->terminate_on =
|
||||
stasis_app_recording_termination_parse(args->terminate_on);
|
||||
options->if_exists =
|
||||
stasis_app_recording_if_exists_parse(args->if_exists);
|
||||
options->beep = args->beep;
|
||||
|
||||
recording = stasis_app_control_record(control, options);
|
||||
if (recording == NULL) {
|
||||
switch(errno) {
|
||||
case EINVAL:
|
||||
/* While the arguments are invalid, we should have
|
||||
* caught them prior to calling record.
|
||||
*/
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Error parsing request");
|
||||
break;
|
||||
case EEXIST:
|
||||
ast_ari_response_error(response, 409, "Conflict",
|
||||
"Recording '%s' already in progress",
|
||||
args->name);
|
||||
break;
|
||||
case ENOMEM:
|
||||
ast_ari_response_alloc_failed(response);
|
||||
break;
|
||||
case EPERM:
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Recording name invalid");
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING,
|
||||
"Unrecognized recording error: %s\n",
|
||||
strerror(errno));
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Internal Server Error");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uri_name_maxlen = strlen(args->name) * 3;
|
||||
uri_encoded_name = ast_malloc(uri_name_maxlen);
|
||||
if (!uri_encoded_name) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
|
||||
|
||||
ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
|
||||
if (!recording_url) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
json = stasis_app_recording_to_json(recording);
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_data = ast_calloc(1, sizeof(*thread_data));
|
||||
if (!thread_data) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_data->bridge_channel = record_channel;
|
||||
thread_data->control = control;
|
||||
|
||||
if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
ast_free(thread_data);
|
||||
return;
|
||||
}
|
||||
|
||||
/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
|
||||
record_channel = NULL;
|
||||
control = NULL;
|
||||
|
||||
ast_ari_response_created(response, recording_url, json);
|
||||
}
|
||||
|
||||
void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
|
||||
if (!snapshot) {
|
||||
ast_ari_response_error(
|
||||
response, 404, "Not Found",
|
||||
"Bridge not found");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response,
|
||||
ast_bridge_snapshot_to_json(snapshot));
|
||||
}
|
||||
|
||||
void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
|
||||
if (!bridge) {
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_bridge_destroy(args->bridge_id);
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
struct ao2_iterator i;
|
||||
void *obj;
|
||||
|
||||
caching_topic = ast_bridge_topic_all_cached();
|
||||
if (!caching_topic) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Message bus not initialized");
|
||||
return;
|
||||
}
|
||||
ao2_ref(caching_topic, +1);
|
||||
|
||||
snapshots = stasis_cache_dump(caching_topic, ast_bridge_snapshot_type());
|
||||
if (!snapshots) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
json = ast_json_array_create();
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
i = ao2_iterator_init(snapshots, 0);
|
||||
while ((obj = ao2_iterator_next(&i))) {
|
||||
RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
|
||||
struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
|
||||
if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ao2_iterator_destroy(&i);
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
|
||||
void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
|
||||
RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||
|
||||
if (!bridge) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error",
|
||||
"Unable to create bridge");
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot = ast_bridge_snapshot_create(bridge);
|
||||
if (!snapshot) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Error",
|
||||
"Unable to create snapshot for new bridge");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response,
|
||||
ast_bridge_snapshot_to_json(snapshot));
|
||||
}
|
179
res/ari/resource_bridges.h
Normal file
179
res/ari/resource_bridges.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_bridges.c
|
||||
*
|
||||
* Bridge resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_BRIDGES_H
|
||||
#define _ASTERISK_RESOURCE_BRIDGES_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_bridges() */
|
||||
struct ast_get_bridges_args {
|
||||
};
|
||||
/*!
|
||||
* \brief List active bridges.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_new_bridge() */
|
||||
struct ast_new_bridge_args {
|
||||
/*! \brief Type of bridge to create. */
|
||||
const char *type;
|
||||
};
|
||||
/*!
|
||||
* \brief Create a new bridge.
|
||||
*
|
||||
* This bridge persists until it has been shut down, or Asterisk has been shut down.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_bridge() */
|
||||
struct ast_get_bridge_args {
|
||||
/*! \brief Bridge's id */
|
||||
const char *bridge_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Get bridge details.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_delete_bridge() */
|
||||
struct ast_delete_bridge_args {
|
||||
/*! \brief Bridge's id */
|
||||
const char *bridge_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Shut down a bridge.
|
||||
*
|
||||
* If any channels are in this bridge, they will be removed and resume whatever they were doing beforehand.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_add_channel_to_bridge() */
|
||||
struct ast_add_channel_to_bridge_args {
|
||||
/*! \brief Bridge's id */
|
||||
const char *bridge_id;
|
||||
/*! \brief Channel's id */
|
||||
const char *channel;
|
||||
};
|
||||
/*!
|
||||
* \brief Add a channel to a bridge.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_remove_channel_from_bridge() */
|
||||
struct ast_remove_channel_from_bridge_args {
|
||||
/*! \brief Bridge's id */
|
||||
const char *bridge_id;
|
||||
/*! \brief Channel's id */
|
||||
const char *channel;
|
||||
};
|
||||
/*!
|
||||
* \brief Remove a channel from a bridge.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_play_on_bridge() */
|
||||
struct ast_play_on_bridge_args {
|
||||
/*! \brief Bridge's id */
|
||||
const char *bridge_id;
|
||||
/*! \brief Media's URI to play. */
|
||||
const char *media;
|
||||
/*! \brief For sounds, selects language for sound. */
|
||||
const char *lang;
|
||||
/*! \brief Number of media to skip before playing. */
|
||||
int offsetms;
|
||||
/*! \brief Number of milliseconds to skip for forward/reverse operations. */
|
||||
int skipms;
|
||||
};
|
||||
/*!
|
||||
* \brief Start playback of media on a bridge.
|
||||
*
|
||||
* The media URI may be any of a number of URI's. You may use http: and https: URI's, as well as sound: and recording: URI's. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_record_bridge() */
|
||||
struct ast_record_bridge_args {
|
||||
/*! \brief Bridge's id */
|
||||
const char *bridge_id;
|
||||
/*! \brief Recording's filename */
|
||||
const char *name;
|
||||
/*! \brief Format to encode audio in */
|
||||
const char *format;
|
||||
/*! \brief Maximum duration of the recording, in seconds. 0 for no limit. */
|
||||
int max_duration_seconds;
|
||||
/*! \brief Maximum duration of silence, in seconds. 0 for no limit. */
|
||||
int max_silence_seconds;
|
||||
/*! \brief Action to take if a recording with the same name already exists. */
|
||||
const char *if_exists;
|
||||
/*! \brief Play beep when recording begins */
|
||||
int beep;
|
||||
/*! \brief DTMF input to terminate recording. */
|
||||
const char *terminate_on;
|
||||
};
|
||||
/*!
|
||||
* \brief Start a recording.
|
||||
*
|
||||
* This records the mixed audio from all channels participating in this bridge.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_BRIDGES_H */
|
693
res/ari/resource_channels.c
Normal file
693
res/ari/resource_channels.c
Normal file
@@ -0,0 +1,693 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Implementation for ARI stubs.
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend type="module">res_stasis_app_playback</depend>
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/file.h"
|
||||
#include "asterisk/pbx.h"
|
||||
#include "asterisk/dial.h"
|
||||
#include "asterisk/bridge.h"
|
||||
#include "asterisk/callerid.h"
|
||||
#include "asterisk/stasis_app.h"
|
||||
#include "asterisk/stasis_app_playback.h"
|
||||
#include "asterisk/stasis_app_recording.h"
|
||||
#include "asterisk/stasis_channels.h"
|
||||
#include "resource_channels.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/*!
|
||||
* \brief Finds the control object for a channel, filling the response with an
|
||||
* error, if appropriate.
|
||||
* \param[out] response Response to fill with an error if control is not found.
|
||||
* \param channel_id ID of the channel to lookup.
|
||||
* \return Channel control object.
|
||||
* \return \c NULL if control object does not exist.
|
||||
*/
|
||||
static struct stasis_app_control *find_control(
|
||||
struct ast_ari_response *response,
|
||||
const char *channel_id)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
control = stasis_app_control_find_by_channel_id(channel_id);
|
||||
if (control == NULL) {
|
||||
/* Distinguish between 404 and 409 errors */
|
||||
RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
|
||||
chan = ast_channel_get_by_name(channel_id);
|
||||
if (chan == NULL) {
|
||||
ast_ari_response_error(response, 404, "Not Found",
|
||||
"Channel not found");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_ari_response_error(response, 409, "Conflict",
|
||||
"Channel not in Stasis application");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(control, +1);
|
||||
return control;
|
||||
}
|
||||
|
||||
void ast_ari_dial(struct ast_variable *headers, struct ast_dial_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
struct stasis_app_control *control;
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stasis_app_control_dial(control, args->endpoint, args->timeout)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_continue_in_dialplan(
|
||||
struct ast_variable *headers,
|
||||
struct ast_continue_in_dialplan_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stasis_app_control_continue(control, args->context, args->extension, args->priority)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_answer_channel(struct ast_variable *headers,
|
||||
struct ast_answer_channel_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (stasis_app_control_answer(control) != 0) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Failed to answer channel");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
unsigned int direction = 0;
|
||||
enum ast_frame_type frametype = AST_FRAME_VOICE;
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(args->direction, "in")) {
|
||||
direction = AST_MUTE_DIRECTION_READ;
|
||||
} else if (!strcmp(args->direction, "out")) {
|
||||
direction = AST_MUTE_DIRECTION_WRITE;
|
||||
} else if (!strcmp(args->direction, "both")) {
|
||||
direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
|
||||
} else {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Invalid direction specified");
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_mute(control, direction, frametype);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_channel_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
unsigned int direction = 0;
|
||||
enum ast_frame_type frametype = AST_FRAME_VOICE;
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(args->direction, "in")) {
|
||||
direction = AST_MUTE_DIRECTION_READ;
|
||||
} else if (!strcmp(args->direction, "out")) {
|
||||
direction = AST_MUTE_DIRECTION_WRITE;
|
||||
} else if (!strcmp(args->direction, "both")) {
|
||||
direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
|
||||
} else {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Invalid direction specified");
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_unmute(control, direction, frametype);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
/* Response filled in by find_control */
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_hold(control);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_unhold_channel(struct ast_variable *headers, struct ast_unhold_channel_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
/* Response filled in by find_control */
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_unhold(control);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_moh_start_channel(struct ast_variable *headers, struct ast_moh_start_channel_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
/* Response filled in by find_control */
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_moh_start(control, args->moh_class);
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_moh_stop_channel(struct ast_variable *headers, struct ast_moh_stop_channel_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
/* Response filled in by find_control */
|
||||
return;
|
||||
}
|
||||
|
||||
stasis_app_control_moh_stop(control);
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_play_on_channel(struct ast_variable *headers,
|
||||
struct ast_play_on_channel_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
|
||||
RAII_VAR(char *, playback_url, NULL, ast_free);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
const char *language;
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
/* Response filled in by find_control */
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot = stasis_app_control_get_snapshot(control);
|
||||
if (!snapshot) {
|
||||
ast_ari_response_error(
|
||||
response, 404, "Not Found",
|
||||
"Channel not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args->skipms < 0) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"skipms cannot be negative");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args->offsetms < 0) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"offsetms cannot be negative");
|
||||
return;
|
||||
}
|
||||
|
||||
language = S_OR(args->lang, snapshot->language);
|
||||
|
||||
playback = stasis_app_control_play_uri(control, args->media, language,
|
||||
args->channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args->skipms, args->offsetms);
|
||||
if (!playback) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Failed to queue media for playback");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_asprintf(&playback_url, "/playback/%s",
|
||||
stasis_app_playback_get_id(playback));
|
||||
if (!playback_url) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
json = stasis_app_playback_to_json(playback);
|
||||
if (!json) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_created(response, playback_url, json);
|
||||
}
|
||||
|
||||
void ast_ari_record_channel(struct ast_variable *headers,
|
||||
struct ast_record_channel_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
|
||||
RAII_VAR(char *, recording_url, NULL, ast_free);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
RAII_VAR(struct stasis_app_recording_options *, options, NULL,
|
||||
ao2_cleanup);
|
||||
RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
|
||||
size_t uri_name_maxlen;
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
if (args->max_duration_seconds < 0) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"max_duration_seconds cannot be negative");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args->max_silence_seconds < 0) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"max_silence_seconds cannot be negative");
|
||||
return;
|
||||
}
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
/* Response filled in by find_control */
|
||||
return;
|
||||
}
|
||||
|
||||
options = stasis_app_recording_options_create(args->name, args->format);
|
||||
if (options == NULL) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
}
|
||||
options->max_silence_seconds = args->max_silence_seconds;
|
||||
options->max_duration_seconds = args->max_duration_seconds;
|
||||
options->terminate_on =
|
||||
stasis_app_recording_termination_parse(args->terminate_on);
|
||||
options->if_exists =
|
||||
stasis_app_recording_if_exists_parse(args->if_exists);
|
||||
options->beep = args->beep;
|
||||
|
||||
if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"terminateOn invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (options->if_exists == -1) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"ifExists invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
recording = stasis_app_control_record(control, options);
|
||||
if (recording == NULL) {
|
||||
switch(errno) {
|
||||
case EINVAL:
|
||||
/* While the arguments are invalid, we should have
|
||||
* caught them prior to calling record.
|
||||
*/
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Error parsing request");
|
||||
break;
|
||||
case EEXIST:
|
||||
ast_ari_response_error(response, 409, "Conflict",
|
||||
"Recording '%s' already in progress",
|
||||
args->name);
|
||||
break;
|
||||
case ENOMEM:
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
break;
|
||||
case EPERM:
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Recording name invalid");
|
||||
break;
|
||||
default:
|
||||
ast_log(LOG_WARNING,
|
||||
"Unrecognized recording error: %s\n",
|
||||
strerror(errno));
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Internal Server Error");
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uri_name_maxlen = strlen(args->name) * 3;
|
||||
uri_encoded_name = ast_malloc(uri_name_maxlen);
|
||||
if (!uri_encoded_name) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
return;
|
||||
}
|
||||
ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
|
||||
ast_uri_http);
|
||||
|
||||
ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
|
||||
if (!recording_url) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
json = stasis_app_recording_to_json(recording);
|
||||
if (!json) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Out of memory");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_created(response, recording_url, json);
|
||||
}
|
||||
|
||||
void ast_ari_get_channel(struct ast_variable *headers,
|
||||
struct ast_get_channel_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
|
||||
struct stasis_caching_topic *caching_topic;
|
||||
struct ast_channel_snapshot *snapshot;
|
||||
|
||||
caching_topic = ast_channel_topic_all_cached();
|
||||
if (!caching_topic) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Message bus not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
msg = stasis_cache_get(caching_topic, ast_channel_snapshot_type(),
|
||||
args->channel_id);
|
||||
if (!msg) {
|
||||
ast_ari_response_error(
|
||||
response, 404, "Not Found",
|
||||
"Channel not found");
|
||||
return;
|
||||
}
|
||||
|
||||
snapshot = stasis_message_data(msg);
|
||||
ast_assert(snapshot != NULL);
|
||||
|
||||
ast_ari_response_ok(response,
|
||||
ast_channel_snapshot_to_json(snapshot));
|
||||
}
|
||||
|
||||
void ast_ari_delete_channel(struct ast_variable *headers,
|
||||
struct ast_delete_channel_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
|
||||
|
||||
chan = ast_channel_get_by_name(args->channel_id);
|
||||
if (chan == NULL) {
|
||||
ast_ari_response_error(
|
||||
response, 404, "Not Found",
|
||||
"Channel not found");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_get_channels(struct ast_variable *headers,
|
||||
struct ast_get_channels_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
struct ao2_iterator i;
|
||||
void *obj;
|
||||
|
||||
caching_topic = ast_channel_topic_all_cached();
|
||||
if (!caching_topic) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Message bus not initialized");
|
||||
return;
|
||||
}
|
||||
ao2_ref(caching_topic, +1);
|
||||
|
||||
snapshots = stasis_cache_dump(caching_topic, ast_channel_snapshot_type());
|
||||
if (!snapshots) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
json = ast_json_array_create();
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
i = ao2_iterator_init(snapshots, 0);
|
||||
while ((obj = ao2_iterator_next(&i))) {
|
||||
RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
|
||||
struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
|
||||
int r = ast_json_array_append(
|
||||
json, ast_channel_snapshot_to_json(snapshot));
|
||||
if (r != 0) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ao2_iterator_destroy(&i);
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
|
||||
void ast_ari_originate(struct ast_variable *headers,
|
||||
struct ast_originate_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
char *dialtech;
|
||||
char dialdevice[AST_CHANNEL_NAME];
|
||||
char *caller_id = NULL;
|
||||
char *cid_num = NULL;
|
||||
char *cid_name = NULL;
|
||||
int timeout = 30000;
|
||||
|
||||
char *stuff;
|
||||
|
||||
if (ast_strlen_zero(args->endpoint)) {
|
||||
ast_ari_response_error(response, 400, "Bad Request",
|
||||
"Endpoint must be specified");
|
||||
return;
|
||||
}
|
||||
|
||||
dialtech = ast_strdupa(args->endpoint);
|
||||
if ((stuff = strchr(dialtech, '/'))) {
|
||||
*stuff++ = '\0';
|
||||
ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
|
||||
ast_ari_response_error(response, 400, "Bad Request",
|
||||
"Invalid endpoint specified");
|
||||
return;
|
||||
}
|
||||
|
||||
if (args->timeout > 0) {
|
||||
timeout = args->timeout * 1000;
|
||||
} else if (args->timeout == -1) {
|
||||
timeout = -1;
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args->caller_id)) {
|
||||
caller_id = ast_strdupa(args->caller_id);
|
||||
ast_callerid_parse(caller_id, &cid_name, &cid_num);
|
||||
|
||||
if (ast_is_shrinkable_phonenumber(cid_num)) {
|
||||
ast_shrink_phone_number(cid_num);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ast_strlen_zero(args->app)) {
|
||||
const char *app = "Stasis";
|
||||
|
||||
RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
|
||||
|
||||
if (!appdata) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_str_set(&appdata, 0, "%s", args->app);
|
||||
if (!ast_strlen_zero(args->app_args)) {
|
||||
ast_str_append(&appdata, 0, ",%s", args->app_args);
|
||||
}
|
||||
|
||||
/* originate a channel, putting it into an application */
|
||||
if (ast_pbx_outgoing_app(dialtech, NULL, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, NULL, NULL, NULL)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
} else if (!ast_strlen_zero(args->extension)) {
|
||||
/* originate a channel, sending it to an extension */
|
||||
if (ast_pbx_outgoing_exten(dialtech, NULL, dialdevice, timeout, S_OR(args->context, "default"), args->extension, args->priority ? args->priority : 1, NULL, 0, cid_num, cid_name, NULL, NULL, NULL, 0)) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
ast_ari_response_error(response, 400, "Bad Request",
|
||||
"Application or extension must be specified");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
||||
void ast_ari_get_channel_var(struct ast_variable *headers, struct ast_get_channel_var_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
RAII_VAR(char *, value, NULL, ast_free);
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
value = stasis_app_control_get_channel_var(control, args->variable);
|
||||
|
||||
if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
|
||||
void ast_ari_set_channel_var(struct ast_variable *headers, struct ast_set_channel_var_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
|
||||
|
||||
ast_assert(response != NULL);
|
||||
|
||||
control = find_control(response, args->channel_id);
|
||||
if (control == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ast_strlen_zero(args->variable)) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Variable name is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (stasis_app_control_set_channel_var(control, args->variable, args->value)) {
|
||||
ast_ari_response_error(
|
||||
response, 400, "Bad Request",
|
||||
"Failed to execute function");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_no_content(response);
|
||||
}
|
||||
|
330
res/ari/resource_channels.h
Normal file
330
res/ari/resource_channels.h
Normal file
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_channels.c
|
||||
*
|
||||
* Channel resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_CHANNELS_H
|
||||
#define _ASTERISK_RESOURCE_CHANNELS_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_channels() */
|
||||
struct ast_get_channels_args {
|
||||
};
|
||||
/*!
|
||||
* \brief List active channels.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_channels(struct ast_variable *headers, struct ast_get_channels_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_originate() */
|
||||
struct ast_originate_args {
|
||||
/*! \brief Endpoint to call. */
|
||||
const char *endpoint;
|
||||
/*! \brief The extension to dial after the endpoint answers */
|
||||
const char *extension;
|
||||
/*! \brief The context to dial after the endpoint answers. If omitted, uses 'default' */
|
||||
const char *context;
|
||||
/*! \brief The priority to dial after the endpoint answers. If omitted, uses 1 */
|
||||
long priority;
|
||||
/*! \brief The application name to pass to the Stasis application. */
|
||||
const char *app;
|
||||
/*! \brief The application arguments to pass to the Stasis application. */
|
||||
const char *app_args;
|
||||
/*! \brief CallerID to use when dialing the endpoint or extension. */
|
||||
const char *caller_id;
|
||||
/*! \brief Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
|
||||
int timeout;
|
||||
};
|
||||
/*!
|
||||
* \brief Create a new channel (originate).
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_originate(struct ast_variable *headers, struct ast_originate_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_channel() */
|
||||
struct ast_get_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Channel details.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_channel(struct ast_variable *headers, struct ast_get_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_delete_channel() */
|
||||
struct ast_delete_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Delete (i.e. hangup) a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_delete_channel(struct ast_variable *headers, struct ast_delete_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_dial() */
|
||||
struct ast_dial_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief Endpoint to call. If not specified, dial is routed via dialplan */
|
||||
const char *endpoint;
|
||||
/*! \brief Extension to dial */
|
||||
const char *extension;
|
||||
/*! \brief When routing via dialplan, the context use. If omitted, uses 'default' */
|
||||
const char *context;
|
||||
/*! \brief Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
|
||||
int timeout;
|
||||
};
|
||||
/*!
|
||||
* \brief Create a new channel (originate) and bridge to this channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_dial(struct ast_variable *headers, struct ast_dial_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_continue_in_dialplan() */
|
||||
struct ast_continue_in_dialplan_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief The context to continue to. */
|
||||
const char *context;
|
||||
/*! \brief The extension to continue to. */
|
||||
const char *extension;
|
||||
/*! \brief The priority to continue to. */
|
||||
int priority;
|
||||
};
|
||||
/*!
|
||||
* \brief Exit application; continue execution in the dialplan.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_continue_in_dialplan(struct ast_variable *headers, struct ast_continue_in_dialplan_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_answer_channel() */
|
||||
struct ast_answer_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Answer a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_answer_channel(struct ast_variable *headers, struct ast_answer_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_mute_channel() */
|
||||
struct ast_mute_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief Direction in which to mute audio */
|
||||
const char *direction;
|
||||
};
|
||||
/*!
|
||||
* \brief Mute a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_unmute_channel() */
|
||||
struct ast_unmute_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief Direction in which to unmute audio */
|
||||
const char *direction;
|
||||
};
|
||||
/*!
|
||||
* \brief Unmute a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_hold_channel() */
|
||||
struct ast_hold_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Hold a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_unhold_channel() */
|
||||
struct ast_unhold_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Remove a channel from hold.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_unhold_channel(struct ast_variable *headers, struct ast_unhold_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_moh_start_channel() */
|
||||
struct ast_moh_start_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief Music on hold class to use */
|
||||
const char *moh_class;
|
||||
};
|
||||
/*!
|
||||
* \brief Play music on hold to a channel.
|
||||
*
|
||||
* Using media operations such as playOnChannel on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_moh_start_channel(struct ast_variable *headers, struct ast_moh_start_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_moh_stop_channel() */
|
||||
struct ast_moh_stop_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Stop playing music on hold to a channel.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_moh_stop_channel(struct ast_variable *headers, struct ast_moh_stop_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_play_on_channel() */
|
||||
struct ast_play_on_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief Media's URI to play. */
|
||||
const char *media;
|
||||
/*! \brief For sounds, selects language for sound. */
|
||||
const char *lang;
|
||||
/*! \brief Number of media to skip before playing. */
|
||||
int offsetms;
|
||||
/*! \brief Number of milliseconds to skip for forward/reverse operations. */
|
||||
int skipms;
|
||||
};
|
||||
/*!
|
||||
* \brief Start playback of media.
|
||||
*
|
||||
* The media URI may be any of a number of URI's. You may use http: and https: URI's, as well as sound: and recording: URI's. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_play_on_channel(struct ast_variable *headers, struct ast_play_on_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_record_channel() */
|
||||
struct ast_record_channel_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief Recording's filename */
|
||||
const char *name;
|
||||
/*! \brief Format to encode audio in */
|
||||
const char *format;
|
||||
/*! \brief Maximum duration of the recording, in seconds. 0 for no limit */
|
||||
int max_duration_seconds;
|
||||
/*! \brief Maximum duration of silence, in seconds. 0 for no limit */
|
||||
int max_silence_seconds;
|
||||
/*! \brief Action to take if a recording with the same name already exists. */
|
||||
const char *if_exists;
|
||||
/*! \brief Play beep when recording begins */
|
||||
int beep;
|
||||
/*! \brief DTMF input to terminate recording */
|
||||
const char *terminate_on;
|
||||
};
|
||||
/*!
|
||||
* \brief Start a recording.
|
||||
*
|
||||
* Record audio from a channel. Note that this will not capture audio sent to the channel. The bridge itself has a record feature if that's what you want.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_record_channel(struct ast_variable *headers, struct ast_record_channel_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_channel_var() */
|
||||
struct ast_get_channel_var_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief The channel variable or function to get */
|
||||
const char *variable;
|
||||
};
|
||||
/*!
|
||||
* \brief Get the value of a channel variable or function.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_channel_var(struct ast_variable *headers, struct ast_get_channel_var_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_set_channel_var() */
|
||||
struct ast_set_channel_var_args {
|
||||
/*! \brief Channel's id */
|
||||
const char *channel_id;
|
||||
/*! \brief The channel variable or function to set */
|
||||
const char *variable;
|
||||
/*! \brief The value to set the variable to */
|
||||
const char *value;
|
||||
};
|
||||
/*!
|
||||
* \brief Set the value of a channel variable or function.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_set_channel_var(struct ast_variable *headers, struct ast_set_channel_var_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_CHANNELS_H */
|
157
res/ari/resource_endpoints.c
Normal file
157
res/ari/resource_endpoints.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 /api-docs/endpoints.{format} implementation- Endpoint resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "resource_endpoints.h"
|
||||
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/stasis.h"
|
||||
#include "asterisk/stasis_endpoints.h"
|
||||
|
||||
void ast_ari_get_endpoints(struct ast_variable *headers,
|
||||
struct ast_get_endpoints_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
struct ao2_iterator i;
|
||||
void *obj;
|
||||
|
||||
caching_topic = ast_endpoint_topic_all_cached();
|
||||
if (!caching_topic) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Message bus not initialized");
|
||||
return;
|
||||
}
|
||||
ao2_ref(caching_topic, +1);
|
||||
|
||||
snapshots = stasis_cache_dump(caching_topic, ast_endpoint_snapshot_type());
|
||||
if (!snapshots) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
json = ast_json_array_create();
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
i = ao2_iterator_init(snapshots, 0);
|
||||
while ((obj = ao2_iterator_next(&i))) {
|
||||
RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
|
||||
struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
|
||||
int r = ast_json_array_append(
|
||||
json, ast_endpoint_snapshot_to_json(snapshot));
|
||||
if (r != 0) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ao2_iterator_destroy(&i);
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
void ast_ari_get_endpoints_by_tech(struct ast_variable *headers,
|
||||
struct ast_get_endpoints_by_tech_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
struct ao2_iterator i;
|
||||
void *obj;
|
||||
|
||||
/* TODO - if tech isn't a recognized type of endpoint, it should 404 */
|
||||
|
||||
caching_topic = ast_endpoint_topic_all_cached();
|
||||
if (!caching_topic) {
|
||||
ast_ari_response_error(
|
||||
response, 500, "Internal Server Error",
|
||||
"Message bus not initialized");
|
||||
return;
|
||||
}
|
||||
ao2_ref(caching_topic, +1);
|
||||
|
||||
snapshots = stasis_cache_dump(caching_topic, ast_endpoint_snapshot_type());
|
||||
if (!snapshots) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
json = ast_json_array_create();
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
i = ao2_iterator_init(snapshots, 0);
|
||||
while ((obj = ao2_iterator_next(&i))) {
|
||||
RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
|
||||
struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
|
||||
int r;
|
||||
|
||||
if (strcmp(args->tech, snapshot->tech) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
r = ast_json_array_append(
|
||||
json, ast_endpoint_snapshot_to_json(snapshot));
|
||||
if (r != 0) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ao2_iterator_destroy(&i);
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
void ast_ari_get_endpoint(struct ast_variable *headers,
|
||||
struct ast_get_endpoint_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||
|
||||
snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource, 0);
|
||||
if (!snapshot) {
|
||||
ast_ari_response_error(response, 404, "Not Found",
|
||||
"Endpoint not found");
|
||||
return;
|
||||
}
|
||||
|
||||
json = ast_endpoint_snapshot_to_json(snapshot);
|
||||
if (!json) {
|
||||
ast_ari_response_alloc_failed(response);
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
82
res/ari/resource_endpoints.h
Normal file
82
res/ari/resource_endpoints.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_endpoints.c
|
||||
*
|
||||
* Endpoint resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_ENDPOINTS_H
|
||||
#define _ASTERISK_RESOURCE_ENDPOINTS_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_endpoints() */
|
||||
struct ast_get_endpoints_args {
|
||||
};
|
||||
/*!
|
||||
* \brief List all endoints.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_endpoints(struct ast_variable *headers, struct ast_get_endpoints_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_endpoints_by_tech() */
|
||||
struct ast_get_endpoints_by_tech_args {
|
||||
/*! \brief Technology of the endpoints (sip,iax2,...) */
|
||||
const char *tech;
|
||||
};
|
||||
/*!
|
||||
* \brief List available endoints for a given endpoint technology.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_endpoints_by_tech(struct ast_variable *headers, struct ast_get_endpoints_by_tech_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_endpoint() */
|
||||
struct ast_get_endpoint_args {
|
||||
/*! \brief Technology of the endpoint */
|
||||
const char *tech;
|
||||
/*! \brief ID of the endpoint */
|
||||
const char *resource;
|
||||
};
|
||||
/*!
|
||||
* \brief Details for an endpoint.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_endpoint(struct ast_variable *headers, struct ast_get_endpoint_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_ENDPOINTS_H */
|
218
res/ari/resource_events.c
Normal file
218
res/ari/resource_events.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 /api-docs/events.{format} implementation- WebSocket resource
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/stasis_app.h"
|
||||
#include "resource_events.h"
|
||||
|
||||
/*! Number of buckets for the Stasis application hash table. Remember to keep it
|
||||
* a prime number!
|
||||
*/
|
||||
#define APPS_NUM_BUCKETS 7
|
||||
|
||||
/*! \brief A connection to the event WebSocket */
|
||||
struct event_session {
|
||||
struct ast_ari_websocket_session *ws_session;
|
||||
struct ao2_container *websocket_apps;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Explicitly shutdown a session.
|
||||
*
|
||||
* An explicit shutdown is necessary, since stasis-app has a reference to this
|
||||
* session. We also need to be sure to null out the \c ws_session field, since
|
||||
* the websocket is about to go away.
|
||||
*
|
||||
* \param session Session info struct.
|
||||
*/
|
||||
static void session_shutdown(struct event_session *session)
|
||||
{
|
||||
struct ao2_iterator i;
|
||||
char *app;
|
||||
SCOPED_AO2LOCK(lock, session);
|
||||
|
||||
i = ao2_iterator_init(session->websocket_apps, 0);
|
||||
while ((app = ao2_iterator_next(&i))) {
|
||||
stasis_app_unregister(app);
|
||||
ao2_cleanup(app);
|
||||
}
|
||||
ao2_iterator_destroy(&i);
|
||||
ao2_cleanup(session->websocket_apps);
|
||||
|
||||
session->websocket_apps = NULL;
|
||||
session->ws_session = NULL;
|
||||
}
|
||||
|
||||
static void session_dtor(void *obj)
|
||||
{
|
||||
#ifdef AST_DEVMODE /* Avoid unused variable warning */
|
||||
struct event_session *session = obj;
|
||||
#endif
|
||||
|
||||
/* session_shutdown should have been called before */
|
||||
ast_assert(session->ws_session == NULL);
|
||||
ast_assert(session->websocket_apps == NULL);
|
||||
}
|
||||
|
||||
static void session_cleanup(struct event_session *session)
|
||||
{
|
||||
session_shutdown(session);
|
||||
ao2_cleanup(session);
|
||||
}
|
||||
|
||||
static struct event_session *session_create(
|
||||
struct ast_ari_websocket_session *ws_session)
|
||||
{
|
||||
RAII_VAR(struct event_session *, session, NULL, ao2_cleanup);
|
||||
|
||||
session = ao2_alloc(sizeof(*session), session_dtor);
|
||||
|
||||
session->ws_session = ws_session;
|
||||
session->websocket_apps =
|
||||
ast_str_container_alloc(APPS_NUM_BUCKETS);
|
||||
|
||||
if (!session->websocket_apps) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ao2_ref(session, +1);
|
||||
return session;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Callback handler for Stasis application messages.
|
||||
*/
|
||||
static void app_handler(void *data, const char *app_name,
|
||||
struct ast_json *message)
|
||||
{
|
||||
struct event_session *session = data;
|
||||
int res;
|
||||
const char *msg_type = S_OR(
|
||||
ast_json_string_get(ast_json_object_get(message, "type")),
|
||||
"");
|
||||
const char *msg_application = S_OR(
|
||||
ast_json_string_get(ast_json_object_get(message, "application")),
|
||||
"");
|
||||
|
||||
/* Determine if we've been replaced */
|
||||
if (strcmp(msg_type, "ApplicationReplaced") == 0 &&
|
||||
strcmp(msg_application, app_name) == 0) {
|
||||
ao2_find(session->websocket_apps, msg_application,
|
||||
OBJ_UNLINK | OBJ_NODATA);
|
||||
}
|
||||
|
||||
res = ast_json_object_set(message, "application",
|
||||
ast_json_string_create(app_name));
|
||||
if(res != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ao2_lock(session);
|
||||
if (session->ws_session) {
|
||||
ast_ari_websocket_session_write(session->ws_session, message);
|
||||
}
|
||||
ao2_unlock(session);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Register for all of the apps given.
|
||||
* \param session Session info struct.
|
||||
* \param app_list Comma seperated list of app names to register.
|
||||
*/
|
||||
static int session_register_apps(struct event_session *session,
|
||||
const char *app_list)
|
||||
{
|
||||
RAII_VAR(char *, to_free, NULL, ast_free);
|
||||
char *apps, *app_name;
|
||||
SCOPED_AO2LOCK(lock, session);
|
||||
|
||||
ast_assert(session->ws_session != NULL);
|
||||
ast_assert(session->websocket_apps != NULL);
|
||||
|
||||
if (!app_list) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
to_free = apps = ast_strdup(app_list);
|
||||
if (!apps) {
|
||||
ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json());
|
||||
return -1;
|
||||
}
|
||||
while ((app_name = strsep(&apps, ","))) {
|
||||
if (ast_str_container_add(session->websocket_apps, app_name)) {
|
||||
ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json());
|
||||
return -1;
|
||||
}
|
||||
|
||||
stasis_app_register(app_name, app_handler, session);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_session,
|
||||
struct ast_variable *headers,
|
||||
struct ast_event_websocket_args *args)
|
||||
{
|
||||
RAII_VAR(struct event_session *, session, NULL, session_cleanup);
|
||||
struct ast_json *msg;
|
||||
int res;
|
||||
|
||||
ast_debug(3, "/events WebSocket connection\n");
|
||||
|
||||
session = session_create(ws_session);
|
||||
if (!session) {
|
||||
ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args->app) {
|
||||
RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
|
||||
|
||||
msg = ast_json_pack("{s: s, s: [s]}",
|
||||
"type", "MissingParams",
|
||||
"params", "app");
|
||||
if (!msg) {
|
||||
msg = ast_json_ref(ast_ari_oom_json());
|
||||
}
|
||||
|
||||
ast_ari_websocket_session_write(session->ws_session, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
res = session_register_apps(session, args->app);
|
||||
if (res != 0) {
|
||||
ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
|
||||
return;
|
||||
}
|
||||
|
||||
/* We don't process any input, but we'll consume it waiting for EOF */
|
||||
while ((msg = ast_ari_websocket_session_read(ws_session))) {
|
||||
ast_json_unref(msg);
|
||||
}
|
||||
}
|
56
res/ari/resource_events.h
Normal file
56
res/ari/resource_events.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_events.c
|
||||
*
|
||||
* WebSocket resource
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_EVENTS_H
|
||||
#define _ASTERISK_RESOURCE_EVENTS_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_event_websocket() */
|
||||
struct ast_event_websocket_args {
|
||||
/*! \brief Comma seperated list of applications to subscribe to. */
|
||||
const char *app;
|
||||
};
|
||||
/*!
|
||||
* \brief WebSocket connection for events.
|
||||
*
|
||||
* \param session ARI WebSocket.
|
||||
* \param headers HTTP headers.
|
||||
* \param args Swagger parameters.
|
||||
*/
|
||||
void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_event_websocket_args *args);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_EVENTS_H */
|
137
res/ari/resource_playback.c
Normal file
137
res/ari/resource_playback.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 /api-docs/playback.{format} implementation- Playback control resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/stasis_app_playback.h"
|
||||
#include "resource_playback.h"
|
||||
|
||||
void ast_ari_get_playback(struct ast_variable *headers,
|
||||
struct ast_get_playback_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
|
||||
playback = stasis_app_playback_find_by_id(args->playback_id);
|
||||
if (playback == NULL) {
|
||||
ast_ari_response_error(response, 404, "Not Found",
|
||||
"Playback not found");
|
||||
return;
|
||||
}
|
||||
|
||||
json = stasis_app_playback_to_json(playback);
|
||||
if (json == NULL) {
|
||||
ast_ari_response_error(response, 500,
|
||||
"Internal Server Error", "Error building response");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
void ast_ari_stop_playback(struct ast_variable *headers,
|
||||
struct ast_stop_playback_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
|
||||
enum stasis_playback_oper_results res;
|
||||
|
||||
playback = stasis_app_playback_find_by_id(args->playback_id);
|
||||
if (playback == NULL) {
|
||||
ast_ari_response_error(response, 404, "Not Found",
|
||||
"Playback not found");
|
||||
return;
|
||||
}
|
||||
|
||||
res = stasis_app_playback_operation(playback, STASIS_PLAYBACK_STOP);
|
||||
|
||||
switch (res) {
|
||||
case STASIS_PLAYBACK_OPER_OK:
|
||||
ast_ari_response_no_content(response);
|
||||
return;
|
||||
case STASIS_PLAYBACK_OPER_FAILED:
|
||||
ast_ari_response_error(response, 500,
|
||||
"Internal Server Error", "Could not stop playback");
|
||||
return;
|
||||
case STASIS_PLAYBACK_OPER_NOT_PLAYING:
|
||||
/* Stop operation should be valid even when not playing */
|
||||
ast_assert(0);
|
||||
ast_ari_response_error(response, 500,
|
||||
"Internal Server Error", "Could not stop playback");
|
||||
return;
|
||||
}
|
||||
}
|
||||
void ast_ari_control_playback(struct ast_variable *headers,
|
||||
struct ast_control_playback_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
|
||||
enum stasis_app_playback_media_operation oper;
|
||||
enum stasis_playback_oper_results res;
|
||||
|
||||
if (strcmp(args->operation, "unpause") == 0) {
|
||||
oper = STASIS_PLAYBACK_UNPAUSE;
|
||||
} else if (strcmp(args->operation, "pause") == 0) {
|
||||
oper = STASIS_PLAYBACK_PAUSE;
|
||||
} else if (strcmp(args->operation, "restart") == 0) {
|
||||
oper = STASIS_PLAYBACK_RESTART;
|
||||
} else if (strcmp(args->operation, "reverse") == 0) {
|
||||
oper = STASIS_PLAYBACK_REVERSE;
|
||||
} else if (strcmp(args->operation, "forward") == 0) {
|
||||
oper = STASIS_PLAYBACK_FORWARD;
|
||||
} else {
|
||||
ast_ari_response_error(response, 400,
|
||||
"Bad Request", "Invalid operation %s",
|
||||
args->operation);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
playback = stasis_app_playback_find_by_id(args->playback_id);
|
||||
if (playback == NULL) {
|
||||
ast_ari_response_error(response, 404, "Not Found",
|
||||
"Playback not found");
|
||||
return;
|
||||
}
|
||||
|
||||
res = stasis_app_playback_operation(playback, oper);
|
||||
|
||||
switch (res) {
|
||||
case STASIS_PLAYBACK_OPER_OK:
|
||||
ast_ari_response_no_content(response);
|
||||
return;
|
||||
case STASIS_PLAYBACK_OPER_FAILED:
|
||||
ast_ari_response_error(response, 500,
|
||||
"Internal Server Error", "Could not %s playback",
|
||||
args->operation);
|
||||
return;
|
||||
case STASIS_PLAYBACK_OPER_NOT_PLAYING:
|
||||
ast_ari_response_error(response, 409, "Conflict",
|
||||
"Can only %s while media is playing", args->operation);
|
||||
return;
|
||||
}
|
||||
}
|
84
res/ari/resource_playback.h
Normal file
84
res/ari/resource_playback.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_playback.c
|
||||
*
|
||||
* Playback control resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_PLAYBACK_H
|
||||
#define _ASTERISK_RESOURCE_PLAYBACK_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_playback() */
|
||||
struct ast_get_playback_args {
|
||||
/*! \brief Playback's id */
|
||||
const char *playback_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Get a playback's details.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_playback(struct ast_variable *headers, struct ast_get_playback_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_stop_playback() */
|
||||
struct ast_stop_playback_args {
|
||||
/*! \brief Playback's id */
|
||||
const char *playback_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Stop a playback.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_stop_playback(struct ast_variable *headers, struct ast_stop_playback_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_control_playback() */
|
||||
struct ast_control_playback_args {
|
||||
/*! \brief Playback's id */
|
||||
const char *playback_id;
|
||||
/*! \brief Operation to perform on the playback. */
|
||||
const char *operation;
|
||||
};
|
||||
/*!
|
||||
* \brief Get a playback's details.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_control_playback(struct ast_variable *headers, struct ast_control_playback_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_PLAYBACK_H */
|
97
res/ari/resource_recordings.c
Normal file
97
res/ari/resource_recordings.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 /api-docs/recordings.{format} implementation- Recording resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "asterisk/stasis_app_recording.h"
|
||||
#include "resource_recordings.h"
|
||||
|
||||
void ast_ari_get_stored_recordings(struct ast_variable *headers, struct ast_get_stored_recordings_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_get_stored_recordings\n");
|
||||
}
|
||||
void ast_ari_get_stored_recording(struct ast_variable *headers, struct ast_get_stored_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_get_stored_recording\n");
|
||||
}
|
||||
void ast_ari_delete_stored_recording(struct ast_variable *headers, struct ast_delete_stored_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_delete_stored_recording\n");
|
||||
}
|
||||
void ast_ari_get_live_recordings(struct ast_variable *headers, struct ast_get_live_recordings_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_get_live_recordings\n");
|
||||
}
|
||||
|
||||
void ast_ari_get_live_recording(struct ast_variable *headers,
|
||||
struct ast_get_live_recording_args *args,
|
||||
struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||
|
||||
recording = stasis_app_recording_find_by_name(args->recording_name);
|
||||
if (recording == NULL) {
|
||||
ast_ari_response_error(response, 404, "Not Found",
|
||||
"Recording not found");
|
||||
return;
|
||||
}
|
||||
|
||||
json = stasis_app_recording_to_json(recording);
|
||||
if (json == NULL) {
|
||||
ast_ari_response_error(response, 500,
|
||||
"Internal Server Error", "Error building response");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, ast_json_ref(json));
|
||||
}
|
||||
|
||||
void ast_ari_cancel_recording(struct ast_variable *headers, struct ast_cancel_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_cancel_recording\n");
|
||||
}
|
||||
void ast_ari_stop_recording(struct ast_variable *headers, struct ast_stop_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_stop_recording\n");
|
||||
}
|
||||
void ast_ari_pause_recording(struct ast_variable *headers, struct ast_pause_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_pause_recording\n");
|
||||
}
|
||||
void ast_ari_unpause_recording(struct ast_variable *headers, struct ast_unpause_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_unpause_recording\n");
|
||||
}
|
||||
void ast_ari_mute_recording(struct ast_variable *headers, struct ast_mute_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_mute_recording\n");
|
||||
}
|
||||
void ast_ari_unmute_recording(struct ast_variable *headers, struct ast_unmute_recording_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
ast_log(LOG_ERROR, "TODO: ast_ari_unmute_recording\n");
|
||||
}
|
186
res/ari/resource_recordings.h
Normal file
186
res/ari/resource_recordings.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_recordings.c
|
||||
*
|
||||
* Recording resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_RECORDINGS_H
|
||||
#define _ASTERISK_RESOURCE_RECORDINGS_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_stored_recordings() */
|
||||
struct ast_get_stored_recordings_args {
|
||||
};
|
||||
/*!
|
||||
* \brief List recordings that are complete.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_stored_recordings(struct ast_variable *headers, struct ast_get_stored_recordings_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_stored_recording() */
|
||||
struct ast_get_stored_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Get a stored recording's details.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_stored_recording(struct ast_variable *headers, struct ast_get_stored_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_delete_stored_recording() */
|
||||
struct ast_delete_stored_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Delete a stored recording.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_delete_stored_recording(struct ast_variable *headers, struct ast_delete_stored_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_live_recordings() */
|
||||
struct ast_get_live_recordings_args {
|
||||
};
|
||||
/*!
|
||||
* \brief List libe recordings.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_live_recordings(struct ast_variable *headers, struct ast_get_live_recordings_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_live_recording() */
|
||||
struct ast_get_live_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief List live recordings.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_live_recording(struct ast_variable *headers, struct ast_get_live_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_cancel_recording() */
|
||||
struct ast_cancel_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Stop a live recording and discard it.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_cancel_recording(struct ast_variable *headers, struct ast_cancel_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_stop_recording() */
|
||||
struct ast_stop_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Stop a live recording and store it.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_stop_recording(struct ast_variable *headers, struct ast_stop_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_pause_recording() */
|
||||
struct ast_pause_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Pause a live recording.
|
||||
*
|
||||
* Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_pause_recording(struct ast_variable *headers, struct ast_pause_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_unpause_recording() */
|
||||
struct ast_unpause_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Unpause a live recording.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_unpause_recording(struct ast_variable *headers, struct ast_unpause_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_mute_recording() */
|
||||
struct ast_mute_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Mute a live recording.
|
||||
*
|
||||
* Muting a recording suspends silence detection, which will be restarted when the recording is unmuted.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_mute_recording(struct ast_variable *headers, struct ast_mute_recording_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_unmute_recording() */
|
||||
struct ast_unmute_recording_args {
|
||||
/*! \brief The name of the recording */
|
||||
const char *recording_name;
|
||||
};
|
||||
/*!
|
||||
* \brief Unmute a live recording.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_unmute_recording(struct ast_variable *headers, struct ast_unmute_recording_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_RECORDINGS_H */
|
220
res/ari/resource_sounds.c
Normal file
220
res/ari/resource_sounds.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 /api-docs/sounds.{format} implementation- Sound resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
|
||||
#include "resource_sounds.h"
|
||||
#include "asterisk/media_index.h"
|
||||
#include "asterisk/sounds_index.h"
|
||||
#include "asterisk/format.h"
|
||||
#include "asterisk/format_cap.h"
|
||||
#include "asterisk/json.h"
|
||||
|
||||
/*! \brief arguments that are necessary for adding format/lang pairs */
|
||||
struct lang_format_info {
|
||||
struct ast_json *format_list; /*!< The embedded array to which format/lang pairs should be added */
|
||||
const char *filename; /*!< Name of the file for which to add format/lang pairs */
|
||||
const char *format_filter; /*!< Format filter provided in the request */
|
||||
};
|
||||
|
||||
/*! \brief Add format/lang pairs to the array embedded in the sound object */
|
||||
static int add_format_information_cb(void *obj, void *arg, int flags)
|
||||
{
|
||||
char *language = obj;
|
||||
struct lang_format_info *args = arg;
|
||||
struct ast_format format;
|
||||
RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
|
||||
RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
|
||||
|
||||
if (!sounds_index) {
|
||||
return CMP_STOP;
|
||||
}
|
||||
|
||||
cap = ast_media_get_format_cap(sounds_index, args->filename, language);
|
||||
if (!cap) {
|
||||
return CMP_STOP;
|
||||
}
|
||||
|
||||
ast_format_cap_iter_start(cap);
|
||||
while (!ast_format_cap_iter_next(cap, &format)) {
|
||||
struct ast_json *lang_format_pair;
|
||||
const char *format_name = ast_getformatname(&format);
|
||||
|
||||
if (!ast_strlen_zero(args->format_filter)
|
||||
&& strcmp(args->format_filter, format_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lang_format_pair = ast_json_pack("{s: s, s: s}",
|
||||
"language", language,
|
||||
"format", format_name);
|
||||
if (!lang_format_pair) {
|
||||
ast_format_cap_iter_end(cap);
|
||||
return CMP_STOP;
|
||||
}
|
||||
|
||||
ast_json_array_append(args->format_list, lang_format_pair);
|
||||
}
|
||||
ast_format_cap_iter_end(cap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Filter out all languages not matching the specified language */
|
||||
static int filter_langs_cb(void *obj, void *arg, int flags)
|
||||
{
|
||||
char *lang_filter = arg;
|
||||
char *lang = obj;
|
||||
if (strcmp(lang, lang_filter)) {
|
||||
return CMP_MATCH;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! \brief Generate a Sound structure as documented in sounds.json for the specified filename */
|
||||
static struct ast_json *create_sound_blob(const char *filename, struct ast_get_sounds_args *args)
|
||||
{
|
||||
RAII_VAR(struct ast_json *, sound, NULL, ast_json_unref);
|
||||
RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
|
||||
const char *description;
|
||||
struct ast_json *format_lang_list;
|
||||
struct lang_format_info info;
|
||||
RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
|
||||
|
||||
if (!sounds_index) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
description = ast_media_get_description(sounds_index, filename, "en");
|
||||
if (ast_strlen_zero(description)) {
|
||||
sound = ast_json_pack("{s: s, s: []}",
|
||||
"id", filename,
|
||||
"formats");
|
||||
} else {
|
||||
sound = ast_json_pack("{s: s, s: s, s: []}",
|
||||
"id", filename,
|
||||
"text", description,
|
||||
"formats");
|
||||
}
|
||||
if (!sound) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
format_lang_list = ast_json_object_get(sound, "formats");
|
||||
if (!format_lang_list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
languages = ast_media_get_variants(sounds_index, filename);
|
||||
if (!languages || !ao2_container_count(languages)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* filter requested languages */
|
||||
if (args && !ast_strlen_zero(args->lang)) {
|
||||
char *lang_filter = ast_strdupa(args->lang);
|
||||
ao2_callback(languages, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, filter_langs_cb, lang_filter);
|
||||
if (!languages || !ao2_container_count(languages)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
info.filename = filename;
|
||||
info.format_list = format_lang_list;
|
||||
info.format_filter = NULL;
|
||||
if (args) {
|
||||
info.format_filter = args->format;
|
||||
}
|
||||
ao2_callback(languages, OBJ_NODATA, add_format_information_cb, &info);
|
||||
|
||||
/* no format/lang pairs for this sound so nothing to return */
|
||||
if (!ast_json_array_size(format_lang_list)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ast_json_ref(sound);
|
||||
}
|
||||
|
||||
/*! \brief Generate a Sound structure and append it to the output blob */
|
||||
static int append_sound_cb(void *obj, void *arg, void *data, int flags)
|
||||
{
|
||||
struct ast_json *sounds_array = arg;
|
||||
char *filename = obj;
|
||||
struct ast_get_sounds_args *args = data;
|
||||
struct ast_json *sound_blob = create_sound_blob(filename, args);
|
||||
if (!sound_blob) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_json_array_append(sounds_array, sound_blob);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ast_ari_get_sounds(struct ast_variable *headers, struct ast_get_sounds_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
RAII_VAR(struct ao2_container *, sound_files, NULL, ao2_cleanup);
|
||||
struct ast_json *sounds_blob;
|
||||
RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
|
||||
|
||||
if (!sounds_index) {
|
||||
ast_ari_response_error(response, 500, "Internal Error", "Sounds index not available");
|
||||
return;
|
||||
}
|
||||
|
||||
sound_files = ast_media_get_media(sounds_index);
|
||||
if (!sound_files) {
|
||||
ast_ari_response_error(response, 500, "Internal Error", "Allocation Error");
|
||||
return;
|
||||
}
|
||||
|
||||
sounds_blob = ast_json_array_create();
|
||||
if (!sounds_blob) {
|
||||
ast_ari_response_error(response, 500, "Internal Error", "Allocation Error");
|
||||
return;
|
||||
}
|
||||
|
||||
ao2_callback_data(sound_files, OBJ_NODATA, append_sound_cb, sounds_blob, args);
|
||||
|
||||
if (!ast_json_array_size(sounds_blob)) {
|
||||
ast_ari_response_error(response, 404, "Not Found", "No sounds found that matched the query");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, sounds_blob);
|
||||
}
|
||||
|
||||
void ast_ari_get_stored_sound(struct ast_variable *headers, struct ast_get_stored_sound_args *args, struct ast_ari_response *response)
|
||||
{
|
||||
struct ast_json *sound_blob;
|
||||
|
||||
sound_blob = create_sound_blob(args->sound_id, NULL);
|
||||
if (!sound_blob) {
|
||||
ast_ari_response_error(response, 404, "Not Found", "Sound not found");
|
||||
return;
|
||||
}
|
||||
|
||||
ast_ari_response_ok(response, sound_blob);
|
||||
}
|
69
res/ari/resource_sounds.h
Normal file
69
res/ari/resource_sounds.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Asterisk -- An open source telephony toolkit.
|
||||
*
|
||||
* Copyright (C) 2012 - 2013, Digium, Inc.
|
||||
*
|
||||
* David M. Lee, II <dlee@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 Generated file - declares stubs to be implemented in
|
||||
* res/ari/resource_sounds.c
|
||||
*
|
||||
* Sound resources
|
||||
*
|
||||
* \author David M. Lee, II <dlee@digium.com>
|
||||
*/
|
||||
|
||||
/*
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* !!!!! DO NOT EDIT !!!!!
|
||||
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
* This file is generated by a mustache template. Please see the original
|
||||
* template in rest-api-templates/ari_resource.h.mustache
|
||||
*/
|
||||
|
||||
#ifndef _ASTERISK_RESOURCE_SOUNDS_H
|
||||
#define _ASTERISK_RESOURCE_SOUNDS_H
|
||||
|
||||
#include "asterisk/ari.h"
|
||||
|
||||
/*! \brief Argument struct for ast_ari_get_sounds() */
|
||||
struct ast_get_sounds_args {
|
||||
const char *lang;
|
||||
const char *format;
|
||||
};
|
||||
/*!
|
||||
* \brief List all sounds.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_sounds(struct ast_variable *headers, struct ast_get_sounds_args *args, struct ast_ari_response *response);
|
||||
/*! \brief Argument struct for ast_ari_get_stored_sound() */
|
||||
struct ast_get_stored_sound_args {
|
||||
/*! \brief Sound's id */
|
||||
const char *sound_id;
|
||||
};
|
||||
/*!
|
||||
* \brief Get a sound's details.
|
||||
*
|
||||
* \param headers HTTP headers
|
||||
* \param args Swagger parameters
|
||||
* \param[out] response HTTP response
|
||||
*/
|
||||
void ast_ari_get_stored_sound(struct ast_variable *headers, struct ast_get_stored_sound_args *args, struct ast_ari_response *response);
|
||||
|
||||
#endif /* _ASTERISK_RESOURCE_SOUNDS_H */
|
Reference in New Issue
Block a user