<p>Joshua Colp has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/13520">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip_pubsub: Add ability to persist generator state information.<br><br>Some body generators, such as dialog-info+xml, require storing state<br>information which is then conveyed in the NOTIFY request itself. Up<br>until now there was no way for such body generators to persist this<br>information.<br><br>Two new API calls have been added to allow body generators to set and<br>get persisted data. This data is persisted out alongside the normal<br>persistence information and allows the body generator to restore<br>state information or to simply use this for normal storage of state.<br>State is stored in the form of a string and it is up to the body<br>generator to interpret this as needed.<br><br>The dialog-info+xml body generator has been updated to take advantage<br>of this to persist the version number.<br><br>ASTERISK-27759<br><br>Change-Id: I5fda56c624fd13c17b3c48e0319b77079e9e27de<br>---<br>M include/asterisk/res_pjsip_pubsub.h<br>M res/res_pjsip_dialog_info_body_generator.c<br>M res/res_pjsip_pubsub.c<br>3 files changed, 139 insertions(+), 47 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/20/13520/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/res_pjsip_pubsub.h b/include/asterisk/res_pjsip_pubsub.h</span><br><span>index 94576d3..6d2307d 100644</span><br><span>--- a/include/asterisk/res_pjsip_pubsub.h</span><br><span>+++ b/include/asterisk/res_pjsip_pubsub.h</span><br><span>@@ -518,6 +518,27 @@</span><br><span> void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.31.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.8.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.2.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Set persistence data for a subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param subscription The subscription to set persistence data on</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param persistence_data The persistence data to set</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, const char *persistence_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 13.31.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 16.8.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since 17.2.0</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve persistence data for a subscription</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param subscription The subscription to retrieve persistence data from</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Register a subscription handler</span><br><span> *</span><br><span> * \retval 0 Handler was registered successfully</span><br><span>diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c</span><br><span>index fa3d710..5e15063 100644</span><br><span>--- a/res/res_pjsip_dialog_info_body_generator.c</span><br><span>+++ b/res/res_pjsip_dialog_info_body_generator.c</span><br><span>@@ -61,51 +61,15 @@</span><br><span> return ast_sip_presence_xml_create_node(state_data->pool, NULL, "dialog-info");</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ast_sip_subscription *sub)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_datastore *datastore = ast_sip_subscription_get_datastore(sub, "dialog-info+xml");</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (datastore) {</span><br><span style="color: hsl(0, 100%, 40%);">- return datastore;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- datastore = ast_sip_subscription_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");</span><br><span style="color: hsl(0, 100%, 40%);">- if (!datastore) {</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">- datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));</span><br><span style="color: hsl(0, 100%, 40%);">- if (!datastore->data || ast_sip_subscription_add_datastore(sub, datastore)) {</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(datastore, -1);</span><br><span style="color: hsl(0, 100%, 40%);">- return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return datastore;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-static unsigned int dialog_info_xml_get_version(struct ast_sip_subscription *sub, unsigned int *version)</span><br><span style="color: hsl(0, 100%, 40%);">-{</span><br><span style="color: hsl(0, 100%, 40%);">- struct ast_datastore *datastore = dialog_info_xml_state_find_or_create(sub);</span><br><span style="color: hsl(0, 100%, 40%);">- struct dialog_info_xml_state *state;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- if (!datastore) {</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- state = datastore->data;</span><br><span style="color: hsl(0, 100%, 40%);">- *version = state->version++;</span><br><span style="color: hsl(0, 100%, 40%);">- ao2_ref(datastore, -1);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-}</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> static int dialog_info_generate_body_content(void *body, void *data)</span><br><span> {</span><br><span> pj_xml_node *dialog_info = body, *dialog, *state;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_datastore *datastore;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct dialog_info_xml_state *datastore_state;</span><br><span> struct ast_sip_exten_state_data *state_data = data;</span><br><span> char *local = ast_strdupa(state_data->local), *stripped, *statestring = NULL;</span><br><span> char *pidfstate = NULL, *pidfnote = NULL;</span><br><span> enum ast_sip_pidf_state local_state;</span><br><span style="color: hsl(0, 100%, 40%);">- unsigned int version;</span><br><span> char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];</span><br><span> struct ast_sip_endpoint *endpoint = NULL;</span><br><span> unsigned int notify_early_inuse_ringing = 0;</span><br><span>@@ -114,9 +78,31 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (dialog_info_xml_get_version(state_data->sub, &version)) {</span><br><span style="color: hsl(0, 100%, 40%);">- ast_log(LOG_WARNING, "dialog-info+xml version could not be retrieved from datastore\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore = ast_sip_subscription_get_datastore(state_data->sub, "state_data->dialog-info+xml");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!datastore) {</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *generator_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore = ast_sip_subscription_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!datastore) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!datastore->data || ast_sip_subscription_add_datastore(state_data->sub, datastore)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(datastore, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore_state = datastore->data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ generator_data = ast_sip_subscription_get_persistence_data(state_data->sub);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(generator_data) && (sscanf(generator_data, "%30u", &datastore_state->version) == 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore_state->version++;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore_state->version = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore_state = datastore->data;</span><br><span style="color: hsl(120, 100%, 40%);">+ datastore_state->version++;</span><br><span> }</span><br><span> </span><br><span> stripped = ast_strip_quoted(local, "<", ">");</span><br><span>@@ -131,9 +117,11 @@</span><br><span> </span><br><span> ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "xmlns", "urn:ietf:params:xml:ns:dialog-info");</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- snprintf(version_str, sizeof(version_str), "%u", version);</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(version_str, sizeof(version_str), "%u", datastore_state->version);</span><br><span> ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "version", version_str);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_subscription_set_persistence_data(state_data->sub, version_str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "state", "full");</span><br><span> ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "entity", sanitized);</span><br><span> </span><br><span>@@ -157,6 +145,8 @@</span><br><span> ast_sip_presence_xml_create_attr(state_data->pool, param, "pvalue", "no");</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(datastore, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c</span><br><span>index 99fdd5f..20cdd00 100644</span><br><span>--- a/res/res_pjsip_pubsub.c</span><br><span>+++ b/res/res_pjsip_pubsub.c</span><br><span>@@ -132,6 +132,11 @@</span><br><span> and therefore the subscription must be deleted after an asterisk restart.</span><br><span> </synopsis></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="generator_data"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>If set, contains persistence data for all generators of content</span><br><span style="color: hsl(120, 100%, 40%);">+ for the subscription.</span><br><span style="color: hsl(120, 100%, 40%);">+ </synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> </configObject></span><br><span> <configObject name="resource_list"></span><br><span> <synopsis>Resource list configuration parameters.</synopsis></span><br><span>@@ -389,6 +394,8 @@</span><br><span> char contact_uri[PJSIP_MAX_URL_SIZE];</span><br><span> /*! Prune subscription on restart */</span><br><span> int prune_on_boot;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Body generator specific persistence data */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_json *generator_data;</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span>@@ -490,6 +497,8 @@</span><br><span> unsigned int full_state;</span><br><span> /*! URI associated with the subscription */</span><br><span> pjsip_sip_uri *uri;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Data to be persisted with the subscription */</span><br><span style="color: hsl(120, 100%, 40%);">+ char *persistence_data;</span><br><span> /*! Name of resource being subscribed to */</span><br><span> char resource[0];</span><br><span> };</span><br><span>@@ -615,6 +624,7 @@</span><br><span> </span><br><span> ast_free(persistence->endpoint);</span><br><span> ast_free(persistence->tag);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_json_unref(persistence->generator_data);</span><br><span> }</span><br><span> </span><br><span> /*! \brief Allocator for subscription persistence */</span><br><span>@@ -1220,6 +1230,7 @@</span><br><span> </span><br><span> AST_VECTOR_FREE(&sub->children);</span><br><span> ao2_cleanup(sub->datastores);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(sub->persistence_data);</span><br><span> ast_free(sub);</span><br><span> }</span><br><span> </span><br><span>@@ -1271,6 +1282,18 @@</span><br><span> pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);</span><br><span> pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (tree->persistence && tree->persistence->generator_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *generator_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If there is any persistence information available for this subscription that was persisted</span><br><span style="color: hsl(120, 100%, 40%);">+ * then make it available so that the NOTIFY has the correct state.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ generator_data = ast_json_object_string_get(tree->persistence->generator_data, resource);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(generator_data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ sub->persistence_data = ast_strdup(generator_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> sub->handler = handler;</span><br><span> sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;</span><br><span> sub->tree = ao2_bump(tree);</span><br><span>@@ -1469,11 +1492,10 @@</span><br><span> static struct sip_subscription_tree *create_subscription_tree(const struct ast_sip_subscription_handler *handler,</span><br><span> struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,</span><br><span> struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,</span><br><span style="color: hsl(0, 100%, 40%);">- pj_status_t *dlg_status)</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_status_t *dlg_status, struct subscription_persistence *persistence)</span><br><span> {</span><br><span> struct sip_subscription_tree *sub_tree;</span><br><span> pjsip_dialog *dlg;</span><br><span style="color: hsl(0, 100%, 40%);">- struct subscription_persistence *persistence;</span><br><span> </span><br><span> sub_tree = allocate_subscription_tree(endpoint, rdata);</span><br><span> if (!sub_tree) {</span><br><span>@@ -1514,6 +1536,9 @@</span><br><span> </span><br><span> sub_tree->notification_batch_interval = tree->notification_batch_interval;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Persistence information needs to be available for all the subscriptions */</span><br><span style="color: hsl(120, 100%, 40%);">+ sub_tree->persistence = ao2_bump(persistence);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);</span><br><span> if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {</span><br><span> sub_tree->is_list = 1;</span><br><span>@@ -1635,7 +1660,7 @@</span><br><span> pj_status_t dlg_status;</span><br><span> </span><br><span> sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,</span><br><span style="color: hsl(0, 100%, 40%);">- &tree, &dlg_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ &tree, &dlg_status, persistence);</span><br><span> if (!sub_tree) {</span><br><span> if (dlg_status != PJ_EEXISTS) {</span><br><span> ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",</span><br><span>@@ -1653,7 +1678,6 @@</span><br><span> ind->sub_tree = ao2_bump(sub_tree);</span><br><span> ind->expires = expires_header->ivalue;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- sub_tree->persistence = ao2_bump(persistence);</span><br><span> subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_RECREATED);</span><br><span> if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {</span><br><span> /* Could not send initial subscribe NOTIFY */</span><br><span>@@ -2710,6 +2734,28 @@</span><br><span> ao2_callback(publication->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, const char *persistence_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(subscription->persistence_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ subscription->persistence_data = ast_strdup(persistence_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (subscription->tree->persistence) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!subscription->tree->persistence->generator_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+ subscription->tree->persistence->generator_data = ast_json_object_create();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!subscription->tree->persistence->generator_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_json_string_create(persistence_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return subscription->persistence_data;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AST_RWLIST_HEAD_STATIC(publish_handlers, ast_sip_publish_handler);</span><br><span> </span><br><span> static int publication_hash_fn(const void *obj, const int flags)</span><br><span>@@ -3076,7 +3122,7 @@</span><br><span> return PJ_TRUE;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);</span><br><span> if (!sub_tree) {</span><br><span> if (dlg_status != PJ_EEXISTS) {</span><br><span> pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);</span><br><span>@@ -4725,6 +4771,39 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct subscription_persistence *persistence = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_json_error error;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We tolerate a failure of the JSON to load and instead start fresh, since this field</span><br><span style="color: hsl(120, 100%, 40%);">+ * originates from the persistence code and not a user.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ persistence->generator_data = ast_json_load_string(var->value, &error);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct subscription_persistence *persistence = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *value;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!persistence->generator_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ value = ast_json_dump_string(persistence->generator_data);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!value) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *buf = ast_strdup(value);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_json_free(value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span> {</span><br><span> struct subscription_persistence *persistence = obj;</span><br><span>@@ -5599,6 +5678,8 @@</span><br><span> CHARFLDSET(struct subscription_persistence, contact_uri));</span><br><span> ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,</span><br><span> FLDSET(struct subscription_persistence, prune_on_boot));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",</span><br><span style="color: hsl(120, 100%, 40%);">+ persistence_generator_data_str2struct, persistence_generator_data_struct2str, NULL, 0, 0);</span><br><span> </span><br><span> if (apply_list_configuration(sorcery)) {</span><br><span> ast_sched_context_destroy(sched);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/13520">change 13520</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/13520"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 13 </div>
<div style="display:none"> Gerrit-Change-Id: I5fda56c624fd13c17b3c48e0319b77079e9e27de </div>
<div style="display:none"> Gerrit-Change-Number: 13520 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>