1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
|
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2008, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*
* Please follow coding guidelines
* http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES
*/
/*! \file
*
* \brief Audiohook inheritance function
*
* \author Mark Michelson <mmichelson@digium.com>
*
* \ingroup functions
*/
/*** MODULEINFO
<support_level>core</support_level>
***/
#include "asterisk.h"
#include "asterisk/datastore.h"
#include "asterisk/channel.h"
#include "asterisk/logger.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
/*** DOCUMENTATION
<function name = "AUDIOHOOK_INHERIT" language="en_US">
<synopsis>
Set whether an audiohook may be inherited to another channel
</synopsis>
<syntax>
<parameter name="source" required="true">
<para>The built-in sources in Asterisk are</para>
<enumlist>
<enum name="MixMonitor" />
<enum name="Chanspy" />
<enum name="Volume" />
<enum name="Speex" />
<enum name="pitch_shift" />
<enum name="JACK_HOOK" />
<enum name="Mute" />
</enumlist>
<para>Note that the names are not case-sensitive</para>
</parameter>
</syntax>
<description>
<para>By enabling audiohook inheritance on the channel, you are giving
permission for an audiohook to be inherited by a descendent channel.
Inheritance may be be disabled at any point as well.</para>
<para>Example scenario:</para>
<para>exten => 2000,1,MixMonitor(blah.wav)</para>
<para>exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)</para>
<para>exten => 2000,n,Dial(SIP/2000)</para>
<para>
</para>
<para>exten => 4000,1,Dial(SIP/4000)</para>
<para>
</para>
<para>exten => 5000,1,MixMonitor(blah2.wav)</para>
<para>exten => 5000,n,Dial(SIP/5000)</para>
<para>
</para>
<para>In this basic dialplan scenario, let's consider the following sample calls</para>
<para>Call 1: Caller dials 2000. The person who answers then executes an attended</para>
<para> transfer to 4000.</para>
<para>Result: Since extension 2000 set MixMonitor to be inheritable, after the</para>
<para> transfer to 4000 has completed, the call will continue to be recorded
to blah.wav</para>
<para>
</para>
<para>Call 2: Caller dials 5000. The person who answers then executes an attended</para>
<para> transfer to 4000.</para>
<para>Result: Since extension 5000 did not set MixMonitor to be inheritable, the</para>
<para> recording will stop once the call has been transferred to 4000.</para>
</description>
</function>
***/
struct inheritable_audiohook {
AST_LIST_ENTRY(inheritable_audiohook) list;
char source[1];
};
struct audiohook_inheritance_datastore {
AST_LIST_HEAD (, inheritable_audiohook) allowed_list;
};
static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
static void audiohook_inheritance_destroy (void *data);
static const struct ast_datastore_info audiohook_inheritance_info = {
.type = "audiohook inheritance",
.destroy = audiohook_inheritance_destroy,
.chan_fixup = audiohook_inheritance_fixup,
};
/*! \brief Move audiohooks as defined by previous calls to the AUDIOHOOK_INHERIT function
*
* Move allowed audiohooks from the old channel to the new channel.
*
* \param data The ast_datastore containing audiohook inheritance information that will be moved
* \param old_chan The "clone" channel from a masquerade. We are moving the audiohook in question off of this channel
* \param new_chan The "original" channel from a masquerade. We are moving the audiohook in question to this channel
* \return Void
*/
static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
{
struct inheritable_audiohook *audiohook = NULL;
struct audiohook_inheritance_datastore *datastore = data;
ast_debug(2, "inheritance fixup occurring for channels %s(%p) and %s(%p)", ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
AST_LIST_TRAVERSE(&datastore->allowed_list, audiohook, list) {
ast_audiohook_move_by_source(old_chan, new_chan, audiohook->source);
ast_debug(3, "Moved audiohook %s from %s(%p) to %s(%p)\n",
audiohook->source, ast_channel_name(old_chan), old_chan, ast_channel_name(new_chan), new_chan);
}
return;
}
/*! \brief Destroy dynamically allocated data on an audiohook_inheritance_datastore
*
* \param data Pointer to the audiohook_inheritance_datastore in question.
* \return Void
*/
static void audiohook_inheritance_destroy(void *data)
{
struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = data;
struct inheritable_audiohook *inheritable_audiohook = NULL;
while ((inheritable_audiohook = AST_LIST_REMOVE_HEAD(&audiohook_inheritance_datastore->allowed_list, list))) {
ast_free(inheritable_audiohook);
}
ast_free(audiohook_inheritance_datastore);
}
/*! \brief create an audiohook_inheritance_datastore and attach it to a channel
*
* \param chan The channel to which we wish to attach the new datastore
* \return Returns the newly created audiohook_inheritance_datastore or NULL on error
*/
static struct audiohook_inheritance_datastore *setup_inheritance_datastore(struct ast_channel *chan)
{
struct ast_datastore *datastore = NULL;
struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = NULL;
if (!(datastore = ast_datastore_alloc(&audiohook_inheritance_info, NULL))) {
return NULL;
}
if (!(audiohook_inheritance_datastore = ast_calloc(1, sizeof(*audiohook_inheritance_datastore)))) {
ast_datastore_free(datastore);
return NULL;
}
datastore->data = audiohook_inheritance_datastore;
ast_channel_lock(chan);
ast_channel_datastore_add(chan, datastore);
ast_channel_unlock(chan);
return audiohook_inheritance_datastore;
}
/*! \brief Create a new inheritable_audiohook structure and add it to an audiohook_inheritance_datastore
*
* \param audiohook_inheritance_datastore The audiohook_inheritance_datastore we want to add the new inheritable_audiohook to
* \param source The audiohook source for the newly created inheritable_audiohook
* \retval 0 Success
* \retval non-zero Failure
*/
static int setup_inheritable_audiohook(struct audiohook_inheritance_datastore *audiohook_inheritance_datastore, const char *source)
{
struct inheritable_audiohook *inheritable_audiohook = NULL;
inheritable_audiohook = ast_calloc(1, sizeof(*inheritable_audiohook) + strlen(source));
if (!inheritable_audiohook) {
return -1;
}
strcpy(inheritable_audiohook->source, source);
AST_LIST_INSERT_TAIL(&audiohook_inheritance_datastore->allowed_list, inheritable_audiohook, list);
ast_debug(3, "Set audiohook %s to be inheritable\n", source);
return 0;
}
/*! \brief Set the permissibility of inheritance for a particular audiohook source on a channel
*
* For details regarding what happens in the function, see the inline comments
*
* \param chan The channel we are operating on
* \param function The name of the dialplan function (AUDIOHOOK_INHERIT)
* \param data The audiohook source for which we are setting inheritance permissions
* \param value The value indicating the permission for audiohook inheritance
*/
static int func_inheritance_write(struct ast_channel *chan, const char *function, char *data, const char *value)
{
int allow;
struct ast_datastore *datastore = NULL;
struct audiohook_inheritance_datastore *inheritance_datastore = NULL;
struct inheritable_audiohook *inheritable_audiohook;
/* Step 1: Get data from function call */
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "No argument provided to INHERITANCE function.\n");
return -1;
}
if (ast_strlen_zero(value)) {
ast_log(LOG_WARNING, "No value provided to INHERITANCE function.\n");
return -1;
}
if (!chan) {
ast_log(LOG_WARNING, "No channel was provided to INHERITANCE function.\n");
return -1;
}
allow = ast_true(value);
/* Step 2: retrieve or set up datastore */
ast_channel_lock(chan);
if (!(datastore = ast_channel_datastore_find(chan, &audiohook_inheritance_info, NULL))) {
ast_channel_unlock(chan);
/* In the case where we cannot find the datastore, we can take a few shortcuts */
if (!allow) {
ast_debug(1, "Audiohook %s is already set to not be inheritable on channel %s\n", data, ast_channel_name(chan));
return 0;
} else if (!(inheritance_datastore = setup_inheritance_datastore(chan))) {
ast_log(LOG_WARNING, "Unable to set up audiohook inheritance datastore on channel %s\n", ast_channel_name(chan));
return -1;
} else {
return setup_inheritable_audiohook(inheritance_datastore, data);
}
} else {
inheritance_datastore = datastore->data;
}
ast_channel_unlock(chan);
/* Step 3: Traverse the list to see if we're trying something redundant */
AST_LIST_TRAVERSE_SAFE_BEGIN(&inheritance_datastore->allowed_list, inheritable_audiohook, list) {
if (!strcasecmp(inheritable_audiohook->source, data)) {
if (allow) {
ast_debug(2, "Audiohook source %s is already set up to be inherited from channel %s\n", data, ast_channel_name(chan));
return 0;
} else {
ast_debug(2, "Removing inheritability of audiohook %s from channel %s\n", data, ast_channel_name(chan));
AST_LIST_REMOVE_CURRENT(list);
ast_free(inheritable_audiohook);
return 0;
}
}
}
AST_LIST_TRAVERSE_SAFE_END;
/* Step 4: There is no step 4 */
/* Step 5: This means we are addressing an audiohook source which we have not encountered yet for the channel. Create a new inheritable
* audiohook structure if we're allowing inheritance, or just return if not
*/
if (allow) {
return setup_inheritable_audiohook(inheritance_datastore, data);
} else {
ast_debug(1, "Audiohook %s is already set to not be inheritable on channel %s\n", data, ast_channel_name(chan));
return 0;
}
}
static struct ast_custom_function inheritance_function = {
.name = "AUDIOHOOK_INHERIT",
.write = func_inheritance_write,
};
static int unload_module(void)
{
return ast_custom_function_unregister(&inheritance_function);
}
static int load_module(void)
{
if (ast_custom_function_register(&inheritance_function)) {
return AST_MODULE_LOAD_DECLINE;
} else {
return AST_MODULE_LOAD_SUCCESS;
}
}
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audiohook inheritance function");
|