<p>Kevin Harwell <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/13520">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, but someone else must approve
  Kevin Harwell: Looks good to me, approved; Approved for Submit

</div><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 JSON 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, 138 insertions(+), 47 deletions(-)<br><br></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..c1b1ec8 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,29 @@</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%);">+ * \note This steals the reference to persistence_data</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, struct ast_json *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 struct ast_json *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..1d94ef5 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,32 @@</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 struct ast_json *version_json;</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%);">+               version_json = ast_sip_subscription_get_persistence_data(state_data->sub);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (version_json) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   datastore_state->version = ast_json_integer_get(version_json);</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 +118,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, ast_json_integer_create(datastore_state->version));</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 +146,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..5712023 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%);">+     struct ast_json *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_json_unref(sub->persistence_data);</span><br><span>    ast_free(sub);</span><br><span> }</span><br><span> </span><br><span>@@ -1271,6 +1282,14 @@</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 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%);">+</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%);">+                sub->persistence_data = ast_json_object_get(tree->persistence->generator_data, resource);</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 +1488,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 +1532,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 +1656,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 +1674,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 +2730,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, struct ast_json *persistence_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_json_unref(subscription->persistence_data);</span><br><span style="color: hsl(120, 100%, 40%);">+    subscription->persistence_data = 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_ref(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 struct ast_json *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 +3118,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 +4767,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 +5674,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: 2 </div>
<div style="display:none"> Gerrit-Owner: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>