Index: channels/iax2-parser.h =================================================================== --- channels/iax2-parser.h (revision 48375) +++ channels/iax2-parser.h (working copy) @@ -73,6 +73,7 @@ unsigned short rr_delay; unsigned int rr_dropped; unsigned int rr_ooo; + struct ast_variable *vars; }; #define DIRECTION_INGRESS 1 Index: channels/chan_iax2.c =================================================================== --- channels/chan_iax2.c (revision 48375) +++ channels/chan_iax2.c (working copy) @@ -2849,6 +2849,7 @@ unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); struct parsed_dial_string pds; struct create_addr_info cai; + struct ast_var_t *var; if ((c->_state != AST_STATE_DOWN) && (c->_state != AST_STATE_RESERVED)) { ast_log(LOG_WARNING, "Channel is already in use (%s)?\n", c->name); @@ -2972,6 +2973,19 @@ /* send the command using the appropriate socket for this peer */ iaxs[callno]->sockfd = cai.sockfd; + /* Add remote vars */ + AST_LIST_TRAVERSE(&c->varshead, var, entries) { + if (!strncmp(ast_var_name(var), "~IAX2~", strlen("~IAX2~"))) { + char tmp[256]; + int i; + /* Automatically divide the value up into sized chunks */ + for (i = 0; i < strlen(ast_var_value(var)); i += 255 - (strlen(ast_var_name(var)) - strlen("~IAX2~") + 1)) { + snprintf(tmp, sizeof(tmp), "%s=%s", ast_var_name(var) + strlen("~IAX2~"), ast_var_value(var) + i); + iax_ie_append_str(&ied, IAX_IE_VARIABLE, tmp); + } + } + } + /* Transmit the string in a "NEW" request */ send_command(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_NEW, 0, ied.buf, ied.pos, -1); @@ -6407,6 +6421,33 @@ return 1; } +static int acf_iaxvar_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + const char *value; + char tmp[256]; + snprintf(tmp, sizeof(tmp), "~IAX2~%s", data); + value = pbx_builtin_getvar_helper(chan, tmp); + ast_copy_string(buf, value ? value : "", len); + return 0; +} + +static int acf_iaxvar_write(struct ast_channel *chan, char *cmd, char *varname, const char *value) +{ + char tmp[256]; + /* Inherit forever */ + snprintf(tmp, sizeof(tmp), "__~IAX2~%s", varname); + pbx_builtin_setvar_helper(chan, tmp, value); + return 0; +} + +static struct ast_custom_function iaxvar_function = { + .name = "IAXVAR", + .synopsis = "Sets or retrieves a remote variable", + .syntax = "IAXVAR()", + .read = acf_iaxvar_read, + .write = acf_iaxvar_write, +}; + static int socket_process(struct iax2_thread *thread) { struct sockaddr_in sin; @@ -6713,6 +6754,9 @@ } else { if (option_debug) ast_log(LOG_DEBUG, "Neat, somebody took away the channel at a magical time but i found it!\n"); + /* Free remote variables (if any) */ + if (ies.vars) + ast_variables_destroy(ies.vars); ast_mutex_unlock(&iaxsl[fr->callno]); return 1; } @@ -6956,6 +7000,18 @@ if(!(c = ast_iax2_new(fr->callno, AST_STATE_RING, format))) iax2_destroy(fr->callno); + else if (ies.vars) { + struct ast_variable *var, *prev = NULL; + char tmp[256]; + for (var = ies.vars; var; var = var->next) { + if (prev) + free(prev); + prev = var; + snprintf(tmp, sizeof(tmp), "__~IAX2~%s", var->name); + pbx_builtin_setvar_helper(c, tmp, var->value); + } + ies.vars = NULL; + } } else { ast_set_flag(&iaxs[fr->callno]->state, IAX_STATE_TBD); /* If this is a TBD call, we're ready but now what... */ @@ -7544,6 +7600,10 @@ iax_ie_append_byte(&ied0, IAX_IE_IAX_UNKNOWN, f.subclass); send_command(iaxs[fr->callno], AST_FRAME_IAX, IAX_COMMAND_UNSUPPORT, 0, ied0.buf, ied0.pos, -1); } + /* Free remote variables (if any) */ + if (ies.vars) + ast_variables_destroy(ies.vars); + /* Don't actually pass these frames along */ if ((f.subclass != IAX_COMMAND_ACK) && (f.subclass != IAX_COMMAND_TXCNT) && @@ -9967,6 +10027,7 @@ static int unload_module(void) { ast_custom_function_unregister(&iaxpeer_function); + ast_custom_function_unregister(&iaxvar_function); return __unload_module(); } @@ -9980,6 +10041,7 @@ struct iax2_peer *peer = NULL; ast_custom_function_register(&iaxpeer_function); + ast_custom_function_register(&iaxvar_function); iax_set_output(iax_debug_output); iax_set_error(iax_error_output); Index: channels/iax2.h =================================================================== --- channels/iax2.h (revision 48375) +++ channels/iax2.h (working copy) @@ -128,6 +128,7 @@ #define IAX_IE_RR_DELAY 49 /* Max playout delay for received frames (in ms) u16 */ #define IAX_IE_RR_DROPPED 50 /* Dropped frames (presumably by jitterbuf) u32 */ #define IAX_IE_RR_OOO 51 /* Frames received Out of Order u32 */ +#define IAX_IE_VARIABLE 52 /* Remote variables */ #define IAX_AUTH_PLAINTEXT (1 << 0) Index: channels/iax2-parser.c =================================================================== --- channels/iax2-parser.c (revision 48375) +++ channels/iax2-parser.c (working copy) @@ -39,6 +39,7 @@ #include "asterisk/frame.h" #include "asterisk/utils.h" #include "asterisk/unaligned.h" +#include "asterisk/config.h" #include "asterisk/lock.h" #include "asterisk/threadstorage.h" @@ -260,6 +261,7 @@ { IAX_IE_RR_DELAY, "RR_DELAY", dump_short }, { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int }, { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int }, + { IAX_IE_VARIABLE, "VARIABLE", dump_string }, }; static struct iax2_ie prov_ies[] = { @@ -611,7 +613,8 @@ /* Parse data into information elements */ int len; int ie; - char tmp[256]; + char tmp[256], *tmp2; + struct ast_variable *var, *var2, *prev; memset(ies, 0, (int)sizeof(struct iax_ies)); ies->msgcount = -1; ies->firmwarever = -1; @@ -896,6 +899,35 @@ ies->rr_ooo = ntohl(get_unaligned_uint32(data + 2)); } break; + case IAX_IE_VARIABLE: + ast_copy_string(tmp, (char *)data + 2, len + 1); + tmp2 = strchr(tmp, '='); + if (tmp2) + *tmp2++ = '\0'; + else + tmp2 = ""; + /* Existing variable or new variable? */ + for (var2 = ies->vars, prev = NULL; var2; prev = var2, var2 = var2->next) { + if (strcmp(tmp, var2->name) == 0) { + int len = strlen(var2->value) + strlen(tmp2) + 1; + char *tmp3 = alloca(len); + snprintf(tmp3, len, "%s%s", var2->value, tmp2); + var = ast_variable_new(tmp, tmp3); + var->next = var2->next; + if (prev) + prev->next = var; + else + ies->vars = var; + free(var2); + break; + } + } + if (!var2) { + var = ast_variable_new(tmp, tmp2); + var->next = ies->vars; + ies->vars = var; + } + break; default: snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len); outputf(tmp);