server CHANGE listed schemas in server's <hello> capabilities list

Introduces nc_server_get_cpblts_version() which returns the capabilities list
with schemas of the specified YANG version only. It is used to generate server's
,hello> message which wrongly included all the YANG schemas, but it is supposed
to contain only YANG 1.0 schemas (besides regular NETCONF capabilities). The
YANG 1.1 schemas are supposed to be listed only via ietf-yang-library data
which provides only the module-set-id into the <hello> content.

(partially) fixes #59
diff --git a/src/session.c b/src/session.c
index 0b11ee2..0b2db50 100644
--- a/src/session.c
+++ b/src/session.c
@@ -766,15 +766,14 @@
 }
 
 API const char **
-nc_server_get_cpblts(struct ly_ctx *ctx)
+nc_server_get_cpblts_version(struct ly_ctx *ctx, LYS_VERSION version)
 {
-    struct lyd_node *child, *child2, *yanglib;
-    struct lyd_node_leaf_list **features = NULL, **deviations = NULL, *ns = NULL, *rev = NULL, *name = NULL, *module_set_id = NULL;
     const char **cpblts;
-    const struct lys_module *mod;
-    int size = 10, count, feat_count = 0, dev_count = 0, i, str_len;
-    unsigned int u;
-#define NC_CPBLT_BUF_LEN 512
+    const struct lys_module *mod, *devmod;
+    int size = 10, count, features_count = 0, dev_count = 0, i, str_len, len;
+    unsigned int u, v, module_set_id;
+    char *s;
+#define NC_CPBLT_BUF_LEN 4096
     char str[NC_CPBLT_BUF_LEN];
 
     if (!ctx) {
@@ -782,12 +781,6 @@
         return NULL;
     }
 
-    yanglib = ly_ctx_info(ctx);
-    if (!yanglib) {
-        ERR("Failed to get ietf-yang-library data from the context.");
-        return NULL;
-    }
-
     cpblts = malloc(size * sizeof *cpblts);
     if (!cpblts) {
         ERRMEM;
@@ -875,110 +868,88 @@
     }
 
     /* models */
-    LY_TREE_FOR(yanglib->prev->child, child) {
-        if (!module_set_id) {
-            if (strcmp(child->prev->schema->name, "module-set-id")) {
-                ERRINT;
-                goto error;
-            }
-            module_set_id = (struct lyd_node_leaf_list *)child->prev;
-        }
-        if (!strcmp(child->schema->name, "module")) {
-            LY_TREE_FOR(child->child, child2) {
-                if (!strcmp(child2->schema->name, "namespace")) {
-                    ns = (struct lyd_node_leaf_list *)child2;
-                } else if (!strcmp(child2->schema->name, "name")) {
-                    name = (struct lyd_node_leaf_list *)child2;
-                } else if (!strcmp(child2->schema->name, "revision")) {
-                    rev = (struct lyd_node_leaf_list *)child2;
-                } else if (!strcmp(child2->schema->name, "feature")) {
-                    features = nc_realloc(features, ++feat_count * sizeof *features);
-                    if (!features) {
-                        ERRMEM;
-                        goto error;
-                    }
-                    features[feat_count - 1] = (struct lyd_node_leaf_list *)child2;
-                } else if (!strcmp(child2->schema->name, "deviation")) {
-                    deviations = nc_realloc(deviations, ++dev_count * sizeof *deviations);
-                    if (!deviations) {
-                        ERRMEM;
-                        goto error;
-                    }
-                    deviations[dev_count - 1] = (struct lyd_node_leaf_list *)child2;
-                }
-            }
-
-            if (!ns || !name || !rev) {
-                ERRINT;
-                continue;
-            }
-
-            str_len = sprintf(str, "%s?module=%s%s%s", ns->value_str, name->value_str,
-                              rev->value_str[0] ? "&revision=" : "", rev->value_str);
-            if (feat_count) {
-                strcat(str, "&features=");
-                str_len += 10;
-                for (i = 0; i < feat_count; ++i) {
-                    if (str_len + 1 + strlen(features[i]->value_str) >= NC_CPBLT_BUF_LEN) {
-                        ERRINT;
-                        break;
-                    }
-                    if (i) {
-                        strcat(str, ",");
-                        ++str_len;
-                    }
-                    strcat(str, features[i]->value_str);
-                    str_len += strlen(features[i]->value_str);
-                }
-            }
-            if (dev_count) {
-                strcat(str, "&deviations=");
-                str_len += 12;
-                for (i = 0; i < dev_count; ++i) {
-                    LY_TREE_FOR(((struct lyd_node *)deviations[i])->child, child2) {
-                        if (!strcmp(child2->schema->name, "name"))
-                            break;
-                    }
-                    if (!child2) {
-                        ERRINT;
-                        continue;
-                    }
-
-                    if (str_len + 1 + strlen(((struct lyd_node_leaf_list *)child2)->value_str) >= NC_CPBLT_BUF_LEN) {
-                        ERRINT;
-                        break;
-                    }
-                    if (i) {
-                        strcat(str, ",");
-                        ++str_len;
-                    }
-                    strcat(str, ((struct lyd_node_leaf_list *)child2)->value_str);
-                    str_len += strlen(((struct lyd_node_leaf_list *)child2)->value_str);
-                }
-            }
-            if (!strcmp(name->value_str, "ietf-yang-library")) {
-                sprintf(str + str_len, "&module-set-id=%s", module_set_id->value_str);
-            }
-
+    u = module_set_id = 0;
+    while ((mod = ly_ctx_get_module_iter(ctx, &u))) {
+        VRB("HELLO module %s", mod->name);
+        if (!strcmp(mod->name, "ietf-yang-library")) {
+            /* ietf-yang-library is always part of the list, but it is specific since it is 1.1 schema */
+            str_len = sprintf(str, "%s?%s%s&module-set-id=%u", mod->ns, mod->rev_size ? "revision=" : "",
+                              mod->rev_size ? mod->rev[0].date : "", ly_ctx_get_module_set_id(ctx));
             add_cpblt(ctx, str, &cpblts, &size, &count);
+            continue;
+        } else if (mod->type) {
+            /* skip submodules */
+            continue;
+        } else if (version == LYS_VERSION_1 && mod->version > version) {
+            /* skip YANG 1.1 schemas */
+            continue;
+        } else if (version == LYS_VERSION_1_1 && mod->version != version) {
+            /* skip YANG 1.0 schemas */
+            continue;
+        }
 
-            ns = NULL;
-            name = NULL;
-            rev = NULL;
-            if (features || feat_count) {
-                free(features);
-                features = NULL;
-                feat_count = 0;
-            }
-            if (deviations || dev_count) {
-                free(deviations);
-                deviations = NULL;
-                dev_count = 0;
+        str_len = sprintf(str, "%s?module=%s%s%s", mod->ns, mod->name,
+                          mod->rev_size ? "&revision=" : "", mod->rev_size ? mod->rev[0].date : "");
+
+        if (mod->features_size) {
+            features_count = 0;
+            for (i = 0; i < mod->features_size; ++i) {
+                if (!(mod->features[i].flags & LYS_FENABLED)) {
+                    continue;
+                }
+                if (!features_count) {
+                    strcat(str, "&features=");
+                    str_len += 10;
+                }
+                len = strlen(mod->features[i].name);
+                if (str_len + 1 + len >= NC_CPBLT_BUF_LEN) {
+                    ERRINT;
+                    break;
+                }
+                if (i) {
+                    strcat(str, ",");
+                    ++str_len;
+                }
+                strcat(str, mod->features[i].name);
+                str_len += len;
+                features_count++;
             }
         }
-    }
 
-    lyd_free_withsiblings(yanglib);
+        if (mod->deviated) {
+            strcat(str, "&deviations=");
+            str_len += 12;
+            dev_count = 0;
+            while ((devmod = ly_ctx_get_module_iter(ctx, &v))) {
+                if (devmod == mod) {
+                    continue;
+                }
+
+                for (i = 0; i < devmod->deviation_size; ++i) {
+                    s = strstr(devmod->deviation[i].target_name, mod->name);
+                    if (s && s[strlen(mod->name)] == ':') {
+                        /* we have the module deviating the module being processed */
+                        len = strlen(devmod->name);
+                        if (str_len + 1 + len >= NC_CPBLT_BUF_LEN) {
+                            ERRINT;
+                            break;
+                        }
+                        if (dev_count) {
+                            strcat(str, ",");
+                            ++str_len;
+                        }
+                        strcat(str, devmod->name);
+                        str_len += len;
+                        dev_count++;
+
+                        break;
+                    }
+                }
+            }
+        }
+
+        add_cpblt(ctx, str, &cpblts, &size, &count);
+    }
 
     /* ending NULL capability */
     add_cpblt(ctx, NULL, &cpblts, &size, &count);
@@ -988,12 +959,15 @@
 error:
 
     free(cpblts);
-    free(features);
-    free(deviations);
-    lyd_free_withsiblings(yanglib);
     return NULL;
 }
 
+API const char **
+nc_server_get_cpblts(struct ly_ctx *ctx)
+{
+    return nc_server_get_cpblts_version(ctx, LYS_VERSION_UNDEF);
+}
+
 static int
 parse_cpblts(struct lyxml_elem *xml, char ***list)
 {
@@ -1093,7 +1067,7 @@
     int r, i;
     const char **cpblts;
 
-    cpblts = nc_server_get_cpblts(session->ctx);
+    cpblts = nc_server_get_cpblts_version(session->ctx, LYS_VERSION_1);
 
     r = nc_write_msg(session, NC_MSG_HELLO, cpblts, &session->id);
 
diff --git a/src/session_server.h b/src/session_server.h
index 88565a2..106a1a1 100644
--- a/src/session_server.h
+++ b/src/session_server.h
@@ -192,7 +192,7 @@
 uint16_t nc_server_get_idle_timeout(void);
 
 /**
- * @brief Get all the server capabilities as will be sent to every client.
+ * @brief Get all the server capabilities including all the schemas.
  *
  * A few capabilities (with-defaults, interleave) depend on the current
  * server options.
@@ -202,6 +202,19 @@
  */
 const char **nc_server_get_cpblts(struct ly_ctx *ctx);
 
+/**
+ * @brief Get the server capabilities including the schemas with the specified YANG version.
+ *
+ * A few capabilities (with-defaults, interleave) depend on the current
+ * server options.
+ *
+ * @param[in] ctx Context to read most capabilities from.
+ * @param[in] version YANG version of the schemas to be included in result, with
+ * LYS_VERSION_UNDEF the result is the same as from nc_server_get_cpblts().
+ * @return Array of capabilities stored in the \p ctx dictionary, NULL on error.
+ */
+const char **nc_server_get_cpblts_version(struct ly_ctx *ctx, LYS_VERSION version);
+
 /**@} Server */
 
 /**