Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c (revision 207316)
+++ channels/chan_sip.c (working copy)
@@ -18617,8 +18617,13 @@
sipmethod = find_sip_method(msg);
owner = p->owner;
- if (owner)
+ if (owner) {
+ char causevar[256], causeval[256];
owner->hangupcause = hangup_sip2cause(resp);
+ snprintf(causevar, sizeof(causevar), "MASTER_CHANNEL(HASH(SIP_CAUSE,%s))", owner->name);
+ snprintf(causeval, sizeof(causeval), "SIP %s", REQ_OFFSET_TO_STR(req, rlPart2));
+ pbx_builtin_setvar_helper(owner, causevar, causeval);
+ }
/* Acknowledge whatever it is destined for */
if ((resp >= 100) && (resp <= 199)) {
Index: funcs/func_channel.c
===================================================================
--- funcs/func_channel.c (revision 207316)
+++ funcs/func_channel.c (working copy)
@@ -55,6 +55,15 @@
will be space-delimited.
+
+
+ Gets or sets variables on the master channel
+
+
+ Allows access to the channel which created the current channel, if any. If the channel is already
+ a master channel, then accesses local channel variables.
+
+
Gets/sets various pieces of information about the channel.
@@ -496,23 +505,49 @@
.read = func_channels_read,
};
+static int func_mchan_read(struct ast_channel *chan, const char *function,
+ char *data, struct ast_str **buf, ssize_t len)
+{
+ struct ast_channel *mchan = ast_channel_get_master(chan);
+ char *template = alloca(4 + strlen(data));
+ sprintf(template, "${%s}", data); /* SAFE */
+ ast_str_substitute_variables(buf, len, mchan ? mchan : chan, template);
+ return 0;
+}
+
+static int func_mchan_write(struct ast_channel *chan, const char *function,
+ char *data, const char *value)
+{
+ struct ast_channel *mchan = ast_channel_get_master(chan);
+ pbx_builtin_setvar_helper(mchan ? mchan : chan, data, value);
+ return 0;
+}
+
+static struct ast_custom_function mchan_function = {
+ .name = "MASTER_CHANNEL",
+ .read2 = func_mchan_read,
+ .write = func_mchan_write,
+};
+
static int unload_module(void)
{
int res = 0;
-
+
res |= ast_custom_function_unregister(&channel_function);
res |= ast_custom_function_unregister(&channels_function);
-
+ res |= ast_custom_function_unregister(&mchan_function);
+
return res;
}
static int load_module(void)
{
int res = 0;
-
+
res |= ast_custom_function_register(&channel_function);
res |= ast_custom_function_register(&channels_function);
-
+ res |= ast_custom_function_register(&mchan_function);
+
return res;
}
Index: include/asterisk/channel.h
===================================================================
--- include/asterisk/channel.h (revision 207316)
+++ include/asterisk/channel.h (working copy)
@@ -2640,6 +2640,14 @@
* '0'
*/
int ast_channel_connected_line_macro(struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const void *connected_info, int caller, int frame);
+
+/*!\since 1.6.3
+ * \brief Retrieve a channel pointer for the channel which created this one, if any.
+ * \param chan Current channel pointer
+ * \retval NULL If the channel is a master channel or was not created by another.
+ * \return Channel pointer. Refcounted, so the pointer MUST be discarded with ast_channel_unref.
+ */
+struct ast_channel *ast_channel_get_master(struct ast_channel *chan);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Index: main/channel.c
===================================================================
--- main/channel.c (revision 207316)
+++ main/channel.c (working copy)
@@ -4361,10 +4361,22 @@
return __ast_request_and_dial(type, format, requestor, data, timeout, outstate, cidnum, cidname, NULL);
}
+static void mchannel_free(void *data)
+{
+ struct ast_channel *mchan = data;
+ ast_channel_unref(mchan);
+}
+
+static struct ast_datastore_info mchan_info = {
+ .type = "MASTERCHANNEL",
+ .destroy = mchannel_free,
+};
+
struct ast_channel *ast_request(const char *type, int format, const struct ast_channel *requestor, void *data, int *cause)
{
struct chanlist *chan;
struct ast_channel *c;
+ struct ast_datastore *mchan_ds;
int capabilities;
int fmt;
int res;
@@ -4406,6 +4418,16 @@
if (!(c = chan->tech->requester(type, capabilities | videoformat | textformat, requestor, data, cause)))
return NULL;
+ /* Insert MASTERCHANNEL datastore */
+ if (requestor) {
+ if (!(mchan_ds = ast_datastore_alloc(&mchan_info, NULL))) {
+ ast_log(LOG_WARNING, "Master channel datastore allocation failed!\n");
+ } else {
+ mchan_ds->data = ast_channel_ref((struct ast_channel *) requestor);
+ ast_channel_datastore_add(c, mchan_ds);
+ }
+ }
+
/* no need to generate a Newchannel event here; it is done in the channel_alloc call */
return c;
}
@@ -7027,6 +7049,15 @@
return retval;
}
+struct ast_channel *ast_channel_get_master(struct ast_channel *chan)
+{
+ struct ast_datastore *mchan_store = ast_channel_datastore_find(chan, &mchan_info, NULL);
+ if (mchan_store) {
+ return ast_channel_ref((struct ast_channel *) mchan_store->data);
+ }
+ return NULL;
+}
+
/* DO NOT PUT ADDITIONAL FUNCTIONS BELOW THIS BOUNDARY
*
* ONLY FUNCTIONS FOR PROVIDING BACKWARDS ABI COMPATIBILITY BELONG HERE