messages FEATURE support for yang-push RPCs
diff --git a/src/messages_client.c b/src/messages_client.c
index 064ccfe..817a60f 100644
--- a/src/messages_client.c
+++ b/src/messages_client.c
@@ -762,6 +762,251 @@
     return (struct nc_rpc *)rpc;
 }
 
+API struct nc_rpc *
+nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const char *stop_time, const char *encoding,
+        uint32_t period, const char *anchor_time, NC_PARAMTYPE paramtype)
+{
+    struct nc_rpc_establishpush *rpc;
+
+    if (!datastore) {
+        ERRARG("datastore");
+        return NULL;
+    } else if (!period) {
+        ERRARG("period");
+        return NULL;
+    }
+
+    if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+        ERR("Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", filter[0]);
+        return NULL;
+    }
+
+    rpc = malloc(sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+
+    rpc->type = NC_RPC_ESTABLISHPUSH;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->datastore = strdup(datastore);
+    } else {
+        rpc->datastore = (char *)datastore;
+    }
+    if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->filter = strdup(filter);
+    } else {
+        rpc->filter = (char *)filter;
+    }
+    if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->stop = strdup(stop_time);
+    } else {
+        rpc->stop = (char *)stop_time;
+    }
+    if (encoding && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->encoding = strdup(encoding);
+    } else {
+        rpc->encoding = (char *)encoding;
+    }
+    rpc->periodic = 1;
+    rpc->period = period;
+    if (anchor_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->anchor_time = strdup(anchor_time);
+    } else {
+        rpc->anchor_time = (char *)anchor_time;
+    }
+    rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+    return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const char *stop_time, const char *encoding,
+        uint32_t dampening_period, int sync_on_start, const char **excluded_change, NC_PARAMTYPE paramtype)
+{
+    struct nc_rpc_establishpush *rpc;
+    uint32_t i;
+
+    if (!datastore) {
+        ERRARG("datastore");
+        return NULL;
+    }
+
+    if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+        ERR("Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", filter[0]);
+        return NULL;
+    }
+
+    rpc = malloc(sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+
+    rpc->type = NC_RPC_ESTABLISHPUSH;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->datastore = strdup(datastore);
+    } else {
+        rpc->datastore = (char *)datastore;
+    }
+    if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->filter = strdup(filter);
+    } else {
+        rpc->filter = (char *)filter;
+    }
+    if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->stop = strdup(stop_time);
+    } else {
+        rpc->stop = (char *)stop_time;
+    }
+    if (encoding && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->encoding = strdup(encoding);
+    } else {
+        rpc->encoding = (char *)encoding;
+    }
+    rpc->periodic = 0;
+    rpc->dampening_period = dampening_period;
+    rpc->sync_on_start = sync_on_start;
+    if (excluded_change && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->excluded_change = NULL;
+        for (i = 0; excluded_change[i]; ++i) {
+            rpc->excluded_change = realloc(rpc->excluded_change, (i + 2) * sizeof *rpc->excluded_change);
+            rpc->excluded_change[i] = strdup(excluded_change[i]);
+            rpc->excluded_change[i + 1] = NULL;
+        }
+    } else {
+        rpc->excluded_change = (char **)excluded_change;
+    }
+    rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+    return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filter, const char *stop_time, uint32_t period,
+        const char *anchor_time, NC_PARAMTYPE paramtype)
+{
+    struct nc_rpc_modifypush *rpc;
+
+    if (!id) {
+        ERRARG("id");
+        return NULL;
+    } else if (!datastore) {
+        ERRARG("datastore");
+        return NULL;
+    }
+
+    if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+        ERR("Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", filter[0]);
+        return NULL;
+    }
+
+    rpc = malloc(sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+
+    rpc->type = NC_RPC_MODIFYPUSH;
+    rpc->id = id;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->datastore = strdup(datastore);
+    } else {
+        rpc->datastore = (char *)datastore;
+    }
+    if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->filter = strdup(filter);
+    } else {
+        rpc->filter = (char *)filter;
+    }
+    if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->stop = strdup(stop_time);
+    } else {
+        rpc->stop = (char *)stop_time;
+    }
+    rpc->periodic = 1;
+    rpc->period = period;
+    if (anchor_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->anchor_time = strdup(anchor_time);
+    } else {
+        rpc->anchor_time = (char *)anchor_time;
+    }
+    rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+    return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filter, const char *stop_time,
+        uint32_t dampening_period, NC_PARAMTYPE paramtype)
+{
+    struct nc_rpc_modifypush *rpc;
+
+    if (!id) {
+        ERRARG("id");
+        return NULL;
+    } else if (!datastore) {
+        ERRARG("datastore");
+        return NULL;
+    }
+
+    if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+        ERR("Filter is not an XML subtree, an XPath expression, not a filter reference (invalid first char '%c').", filter[0]);
+        return NULL;
+    }
+
+    rpc = malloc(sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+
+    rpc->type = NC_RPC_MODIFYPUSH;
+    rpc->id = id;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->datastore = strdup(datastore);
+    } else {
+        rpc->datastore = (char *)datastore;
+    }
+    if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->filter = strdup(filter);
+    } else {
+        rpc->filter = (char *)filter;
+    }
+    if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->stop = strdup(stop_time);
+    } else {
+        rpc->stop = (char *)stop_time;
+    }
+    rpc->periodic = 0;
+    rpc->dampening_period = dampening_period;
+    rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+    return (struct nc_rpc *)rpc;
+}
+
+API struct nc_rpc *
+nc_rpc_resyncsub(uint32_t id)
+{
+    struct nc_rpc_resyncsub *rpc;
+
+    if (!id) {
+        ERRARG("id");
+        return NULL;
+    }
+
+    rpc = malloc(sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+
+    rpc->type = NC_RPC_RESYNCSUB;
+    rpc->id = id;
+
+    return (struct nc_rpc *)rpc;
+}
+
 API void
 nc_rpc_free(struct nc_rpc *rpc)
 {
@@ -780,6 +1025,8 @@
     struct nc_rpc_editdata *rpc_editdata;
     struct nc_rpc_establishsub *rpc_establishsub;
     struct nc_rpc_modifysub *rpc_modifysub;
+    struct nc_rpc_establishpush *rpc_establishpush;
+    struct nc_rpc_modifypush *rpc_modifypush;
     int i;
 
     if (!rpc) {
@@ -900,6 +1147,36 @@
             free(rpc_modifysub->stop);
         }
         break;
+    case NC_RPC_ESTABLISHPUSH:
+        rpc_establishpush = (struct nc_rpc_establishpush *)rpc;
+        if (rpc_establishpush->free) {
+            free(rpc_establishpush->datastore);
+            free(rpc_establishpush->filter);
+            free(rpc_establishpush->stop);
+            free(rpc_establishpush->encoding);
+            if (rpc_establishpush->periodic) {
+                free(rpc_establishpush->anchor_time);
+            } else {
+                if (rpc_establishpush->excluded_change) {
+                    for (i = 0; rpc_establishpush->excluded_change[i]; ++i) {
+                        free(rpc_establishpush->excluded_change[i]);
+                    }
+                    free(rpc_establishpush->excluded_change);
+                }
+            }
+        }
+        break;
+    case NC_RPC_MODIFYPUSH:
+        rpc_modifypush = (struct nc_rpc_modifypush *)rpc;
+        if (rpc_modifypush->free) {
+            free(rpc_modifypush->datastore);
+            free(rpc_modifypush->filter);
+            free(rpc_modifypush->stop);
+            if (rpc_modifypush->periodic) {
+                free(rpc_modifypush->anchor_time);
+            }
+        }
+        break;
     case NC_RPC_UNKNOWN:
     case NC_RPC_LOCK:
     case NC_RPC_UNLOCK:
@@ -907,6 +1184,7 @@
     case NC_RPC_DISCARD:
     case NC_RPC_DELETESUB:
     case NC_RPC_KILLSUB:
+    case NC_RPC_RESYNCSUB:
         /* nothing special needed */
         break;
     }
diff --git a/src/messages_client.h b/src/messages_client.h
index 0504bc3..6feecab 100644
--- a/src/messages_client.h
+++ b/src/messages_client.h
@@ -70,6 +70,11 @@
     NC_RPC_MODIFYSUB,       /**< \<modify-subscription\> RPC. */
     NC_RPC_DELETESUB,       /**< \<delete-subscription\> RPC. */
     NC_RPC_KILLSUB,         /**< \<kill-subscription\> RPC. */
+
+    /* ietf-yang-push */
+    NC_RPC_ESTABLISHPUSH,   /**< \<establish-subscription\> RPC with augments. */
+    NC_RPC_MODIFYPUSH,      /**< \<modify-subscription\> RPC with augments. */
+    NC_RPC_RESYNCSUB,       /**< \<resync-subscription\> RPC. */
 } NC_RPC_TYPE;
 
 /**
@@ -448,6 +453,89 @@
 struct nc_rpc *nc_rpc_killsub(uint32_t id);
 
 /**
+ * @brief Create NETCONF RPC \<establish-subscription\> with augments from ietf-yang-push for a periodic subscription
+ *
+ * For details, see ::nc_rpc.
+ *
+ * @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
+ * @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
+ * or filter reference, selected based on the first character.
+ * @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
+ * @param[in] encoding Optional specific encoding to use.
+ * @param[in] period Subscription period in centiseconds (0.01s).
+ * @param[in] anchor_time Optional anchor datetime for the period.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_establishpush_periodic(const char *datastore, const char *filter, const char *stop_time,
+        const char *encoding, uint32_t period, const char *anchor_time, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<establish-subscription\> with augments from ietf-yang-push for an on-change subscription
+ *
+ * For details, see ::nc_rpc.
+ *
+ * @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
+ * @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
+ * or filter reference, selected based on the first character.
+ * @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
+ * @param[in] encoding Optional specific encoding to use.
+ * @param[in] dampening_period Optional dampening period of the notifications.
+ * @param[in] sync_on_start Whether to send a full push-update notification on subscription start.
+ * @param[in] excluded_change Optional NULL-terminated array of excluded changes.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_establishpush_onchange(const char *datastore, const char *filter, const char *stop_time,
+        const char *encoding, uint32_t dampening_period, int sync_on_start, const char **excluded_change,
+        NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<modify-subscription\> with augments from ietf-yang-push for a periodic subscription
+ *
+ * For details, see ::nc_rpc.
+ *
+ * @param[in] id Subscription ID to modify.
+ * @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
+ * @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
+ * or filter reference, selected based on the first character.
+ * @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
+ * @param[in] period Subscription period in centiseconds (0.01s).
+ * @param[in] anchor_time Optional anchor datetime for the period.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_modifypush_periodic(uint32_t id, const char *datastore, const char *filter, const char *stop_time,
+        uint32_t period, const char *anchor_time, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<modify-subscription\> with augments from ietf-yang-push for an on-change subscription
+ *
+ * For details, see ::nc_rpc.
+ *
+ * @param[in] id Subscription ID to modify.
+ * @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
+ * @param[in] filter Optional filter data, an XML subtree, XPath expression (with JSON prefixes),
+ * or filter reference, selected based on the first character.
+ * @param[in] stop_time Optional YANG datetime identifying the end of the subscription.
+ * @param[in] dampening_period Optional dampening period of the notifications.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_modifypush_onchange(uint32_t id, const char *datastore, const char *filter, const char *stop_time,
+        uint32_t dampening_period, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<resync-subscription\>
+ *
+ * For details, see ::nc_rpc.
+ *
+ * @param[in] id Subscription ID to resync.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_resyncsub(uint32_t id);
+
+/**
  * @brief Free the NETCONF RPC object.
  *
  * @param[in] rpc Object to free.
diff --git a/src/messages_p.h b/src/messages_p.h
index b71f69d..2d9cd85 100644
--- a/src/messages_p.h
+++ b/src/messages_p.h
@@ -213,6 +213,49 @@
     uint32_t id;
 };
 
+struct nc_rpc_establishpush {
+    NC_RPC_TYPE type;        /**< NC_RPC_ESTABLISHPUSH */
+    char *datastore;
+    char *filter;            /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
+    char *stop;
+    char *encoding;
+    int periodic;
+    union {
+        struct {
+            uint32_t period;
+            char *anchor_time;
+        };
+        struct {
+            uint32_t dampening_period;
+            int sync_on_start;
+            char **excluded_change;
+        };
+    };
+    char free;
+};
+
+struct nc_rpc_modifypush {
+    NC_RPC_TYPE type;        /**< NC_RPC_MODIFYPUSH */
+    uint32_t id;
+    char *datastore;
+    char *filter;            /**< XML subtree (starts with '<'), an XPath (starts with '/'), or reference (start with alpha) */
+    char *stop;
+    int periodic;
+    union {
+        struct {
+            uint32_t period;
+            char *anchor_time;
+        };
+        uint32_t dampening_period;
+    };
+    char free;
+};
+
+struct nc_rpc_resyncsub {
+    NC_RPC_TYPE type;        /**< NC_RPC_RESYNCSUB */
+    uint32_t id;
+};
+
 void nc_server_rpc_free(struct nc_server_rpc *rpc);
 
 void nc_client_err_clean(struct nc_err *err, struct ly_ctx *ctx);
diff --git a/src/session_client.c b/src/session_client.c
index bdcfc4b..c7f6c15 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -1752,8 +1752,7 @@
     struct ly_in *in;
     struct lyd_node *tree, *op2;
     const struct lys_module *mod;
-    const char *module_name = NULL;
-    const char *rpc_name = NULL;
+    const char *module_name = NULL, *rpc_name = NULL, *module_check = NULL;
 
     switch (rpc->type) {
     case NC_RPC_ACT_GENERIC:
@@ -1864,6 +1863,20 @@
         module_name = "ietf-subscribed-notifications";
         rpc_name = "kill-subscription";
         break;
+    case NC_RPC_ESTABLISHPUSH:
+        module_name = "ietf-subscribed-notifications";
+        rpc_name = "establish-subscription";
+        module_check = "ietf-yang-push";
+        break;
+    case NC_RPC_MODIFYPUSH:
+        module_name = "ietf-subscribed-notifications";
+        rpc_name = "modify-subscription";
+        module_check = "ietf-yang-push";
+        break;
+    case NC_RPC_RESYNCSUB:
+        module_name = "ietf-yang-push";
+        rpc_name = "resync-subscription";
+        break;
     case NC_RPC_UNKNOWN:
         lyrc = LY_EINT;
         break;
@@ -1879,6 +1892,12 @@
         /* create the operation node */
         lyrc = lyd_new_inner(NULL, mod, rpc_name, 0, op);
     }
+    if (module_check) {
+        if (!ly_ctx_get_module_implemented(session->ctx, module_check)) {
+            ERR("Session %u: missing \"%s\" schema in the context.", session->id, module_check);
+            return -1;
+        }
+    }
 
     if (lyrc) {
         return -1;
@@ -2172,8 +2191,11 @@
     struct nc_rpc_modifysub *rpc_modsub;
     struct nc_rpc_deletesub *rpc_delsub;
     struct nc_rpc_killsub *rpc_killsub;
-    struct lyd_node *data, *node;
-    const struct lys_module *mod = NULL, *ietfncwd;
+    struct nc_rpc_establishpush *rpc_estpush;
+    struct nc_rpc_modifypush *rpc_modpush;
+    struct nc_rpc_resyncsub *rpc_resyncsub;
+    struct lyd_node *data, *node, *cont;
+    const struct lys_module *mod = NULL, *mod2 = NULL, *ietfncwd;
     LY_ERR lyrc;
     int i;
     char str[11];
@@ -2247,6 +2269,26 @@
             return NC_MSG_ERROR;
         }
         break;
+    case NC_RPC_ESTABLISHPUSH:
+    case NC_RPC_MODIFYPUSH:
+        mod = ly_ctx_get_module_implemented(session->ctx, "ietf-subscribed-notifications");
+        if (!mod) {
+            ERR("Session %u: missing \"ietf-subscribed-notifications\" schema in the context.", session->id);
+            return NC_MSG_ERROR;
+        }
+        mod2 = ly_ctx_get_module_implemented(session->ctx, "ietf-yang-push");
+        if (!mod2) {
+            ERR("Session %u: missing \"ietf-yang-push\" schema in the context.", session->id);
+            return NC_MSG_ERROR;
+        }
+        break;
+    case NC_RPC_RESYNCSUB:
+        mod = ly_ctx_get_module_implemented(session->ctx, "ietf-yang-push");
+        if (!mod) {
+            ERR("Session %u: missing \"ietf-yang-push\" schema in the context.", session->id);
+            return NC_MSG_ERROR;
+        }
+        break;
     case NC_RPC_UNKNOWN:
         ERRINT;
         return NC_MSG_ERROR;
@@ -2793,6 +2835,175 @@
         }
         break;
 
+    case NC_RPC_ESTABLISHPUSH:
+        rpc_estpush = (struct nc_rpc_establishpush *)rpc;
+
+        lyd_new_inner(NULL, mod, "establish-subscription", 0, &data);
+
+        if (lyd_new_term(data, mod2, "datastore", rpc_estpush->datastore, 0, NULL)) {
+            lyd_free_tree(data);
+            return NC_MSG_ERROR;
+        }
+
+        if (rpc_estpush->filter) {
+            if (!rpc_estpush->filter[0] || (rpc_estpush->filter[0] == '<')) {
+                lyd_new_any(data, mod2, "datastore-subtree-filter", rpc_estpush->filter, 0, LYD_ANYDATA_XML, 0, &node);
+            } else if (rpc_estpush->filter[0] == '/') {
+                lyd_new_term(data, mod2, "datastore-xpath-filter", rpc_estpush->filter, 0, &node);
+            } else {
+                lyd_new_term(data, mod2, "selection-filter-ref", rpc_estpush->filter, 0, &node);
+            }
+            if (!node) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (rpc_estpush->stop) {
+            if (lyd_new_term(data, mod, "stop-time", rpc_estpush->stop, 0, NULL)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (rpc_estpush->encoding) {
+            if (lyd_new_term(data, mod, "encoding", rpc_estpush->encoding, 0, NULL)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (rpc_estpush->periodic) {
+            if (lyd_new_inner(data, mod2, "periodic", 0, &cont)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            sprintf(str, "%" PRIu32, rpc_estpush->period);
+            if (lyd_new_term(cont, mod2, "period", str, 0, NULL)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            if (rpc_estpush->anchor_time) {
+                if (lyd_new_term(cont, mod2, "anchor-time", rpc_estpush->anchor_time, 0, NULL)) {
+                    lyd_free_tree(data);
+                    return NC_MSG_ERROR;
+                }
+            }
+        } else {
+            if (lyd_new_inner(data, mod2, "on-change", 0, &cont)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            if (rpc_estpush->dampening_period) {
+                sprintf(str, "%" PRIu32, rpc_estpush->dampening_period);
+                if (lyd_new_term(cont, mod2, "dampening-period", str, 0, NULL)) {
+                    lyd_free_tree(data);
+                    return NC_MSG_ERROR;
+                }
+            }
+
+            if (lyd_new_term(cont, mod2, "sync-on-start", rpc_estpush->sync_on_start ? "true" : "false", 0, NULL)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            if (rpc_estpush->excluded_change) {
+                for (i = 0; rpc_estpush->excluded_change[i]; ++i) {
+                    if (lyd_new_term(cont, mod2, "excluded-change", rpc_estpush->excluded_change[i], 0, NULL)) {
+                        lyd_free_tree(data);
+                        return NC_MSG_ERROR;
+                    }
+                }
+            }
+        }
+        break;
+
+    case NC_RPC_MODIFYPUSH:
+        rpc_modpush = (struct nc_rpc_modifypush *)rpc;
+
+        lyd_new_inner(NULL, mod, "modify-subscription", 0, &data);
+
+        sprintf(str, "%u", rpc_modpush->id);
+        if (lyd_new_term(data, mod, "id", str, 0, NULL)) {
+            lyd_free_tree(data);
+            return NC_MSG_ERROR;
+        }
+
+        if (lyd_new_term(data, mod2, "datastore", rpc_modpush->datastore, 0, NULL)) {
+            lyd_free_tree(data);
+            return NC_MSG_ERROR;
+        }
+
+        if (rpc_modpush->filter) {
+            if (!rpc_modpush->filter[0] || (rpc_modpush->filter[0] == '<')) {
+                lyd_new_any(data, mod2, "datastore-subtree-filter", rpc_modpush->filter, 0, LYD_ANYDATA_XML, 0, &node);
+            } else if (rpc_modpush->filter[0] == '/') {
+                lyd_new_term(data, mod2, "datastore-xpath-filter", rpc_modpush->filter, 0, &node);
+            } else {
+                lyd_new_term(data, mod2, "selection-filter-ref", rpc_modpush->filter, 0, &node);
+            }
+            if (!node) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (rpc_modpush->stop) {
+            if (lyd_new_term(data, mod, "stop-time", rpc_modpush->stop, 0, NULL)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (rpc_modpush->periodic) {
+            if (lyd_new_inner(data, mod2, "periodic", 0, &cont)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            sprintf(str, "%" PRIu32, rpc_modpush->period);
+            if (lyd_new_term(cont, mod2, "period", str, 0, NULL)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            if (rpc_modpush->anchor_time) {
+                if (lyd_new_term(cont, mod2, "anchor-time", rpc_modpush->anchor_time, 0, NULL)) {
+                    lyd_free_tree(data);
+                    return NC_MSG_ERROR;
+                }
+            }
+        } else {
+            if (lyd_new_inner(data, mod2, "on-change", 0, &cont)) {
+                lyd_free_tree(data);
+                return NC_MSG_ERROR;
+            }
+
+            if (rpc_modpush->dampening_period) {
+                sprintf(str, "%" PRIu32, rpc_modpush->dampening_period);
+                if (lyd_new_term(cont, mod2, "dampening-period", str, 0, NULL)) {
+                    lyd_free_tree(data);
+                    return NC_MSG_ERROR;
+                }
+            }
+        }
+        break;
+
+    case NC_RPC_RESYNCSUB:
+        rpc_resyncsub = (struct nc_rpc_resyncsub *)rpc;
+
+        lyd_new_inner(NULL, mod, "resync-subscription", 0, &data);
+
+        sprintf(str, "%u", rpc_resyncsub->id);
+        if (lyd_new_term(data, mod, "id", str, 0, NULL)) {
+            lyd_free_tree(data);
+            return NC_MSG_ERROR;
+        }
+        break;
+
     case NC_RPC_UNKNOWN:
         ERRINT;
         return NC_MSG_ERROR;