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