client session BUGFIX accepting non-standard capabilities

Except that also if some capability module fails to load,
the data of it are ignored.

Fixes #18
diff --git a/src/session_client.c b/src/session_client.c
index c019b93..1555991 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -65,19 +65,15 @@
 
 /* SCHEMAS_DIR not used (implicitly) */
 static int
-ctx_check_and_load_model(struct nc_session *session, const char *cpblt)
+ctx_check_and_load_model(struct nc_session *session, const char *module_cpblt)
 {
     const struct lys_module *module;
     char *ptr, *ptr2;
     char *model_name, *revision = NULL, *features = NULL;
 
-    /* parse module */
-    ptr = strstr(cpblt, "module=");
-    if (!ptr) {
-        ERR("Unknown capability \"%s\" could not be parsed.", cpblt);
-        return -1;
-    }
-    ptr += 7;
+    assert(!strncmp(module_cpblt, "module=", 7));
+
+    ptr = (char *)module_cpblt + 7;
     ptr2 = strchr(ptr, '&');
     if (!ptr2) {
         ptr2 = ptr + strlen(ptr);
@@ -85,7 +81,7 @@
     model_name = strndup(ptr, ptr2 - ptr);
 
     /* parse revision */
-    ptr = strstr(cpblt, "revision=");
+    ptr = strstr(module_cpblt, "revision=");
     if (ptr) {
         ptr += 9;
         ptr2 = strchr(ptr, '&');
@@ -110,7 +106,7 @@
     free(model_name);
 
     /* parse features */
-    ptr = strstr(cpblt, "features=");
+    ptr = strstr(module_cpblt, "features=");
     if (ptr) {
         ptr += 9;
         ptr2 = strchr(ptr, '&');
@@ -293,6 +289,7 @@
 int
 nc_ctx_check_and_fill(struct nc_session *session)
 {
+    const char *module_cpblt;
     int i, get_schema_support = 0, ret = 0, r;
     ly_module_clb old_clb = NULL;
     void *old_data = NULL;
@@ -328,42 +325,41 @@
 
     /* load all other models */
     for (i = 0; session->opts.client.cpblts[i]; ++i) {
-        if (!strncmp(session->opts.client.cpblts[i], "urn:ietf:params:netconf:capability", 34)
-                || !strncmp(session->opts.client.cpblts[i], "urn:ietf:params:netconf:base", 28)) {
-            continue;
-        }
-
-        r = ctx_check_and_load_model(session, session->opts.client.cpblts[i]);
-        if (r == -1) {
-            ret = -1;
-            break;
-        }
-
-        /* failed to load schema, but let's try to find it using user callback (or locally, if not set),
-         * if it was using get-schema */
-        if (r == 1) {
-            if (get_schema_support) {
-                VRB("Trying to load the schema from a different source.");
-                /* works even if old_clb is NULL */
-                ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
-                r = ctx_check_and_load_model(session, session->opts.client.cpblts[i]);
+        module_cpblt = strstr(session->opts.client.cpblts[i], "module=");
+        /* this capability requires a module */
+        if (module_cpblt) {
+            r = ctx_check_and_load_model(session, module_cpblt);
+            if (r == -1) {
+                ret = -1;
+                break;
             }
 
-            /* fail again (or no other way to try), too bad */
-            if (r) {
-                ret = 1;
-            }
+            /* failed to load schema, but let's try to find it using user callback (or locally, if not set),
+            * if it was using get-schema */
+            if (r == 1) {
+                if (get_schema_support) {
+                    VRB("Trying to load the schema from a different source.");
+                    /* works even if old_clb is NULL */
+                    ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
+                    r = ctx_check_and_load_model(session, module_cpblt);
+                }
 
-            /* set get-schema callback back */
-            ly_ctx_set_module_clb(session->ctx, &libyang_module_clb, session);
+                /* fail again (or no other way to try), too bad */
+                if (r) {
+                    session->flags |= NC_SESSION_CLIENT_NOT_STRICT;
+                }
+
+                /* set get-schema callback back */
+                ly_ctx_set_module_clb(session->ctx, &libyang_module_clb, session);
+            }
         }
     }
 
     if (old_clb) {
         ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
     }
-    if (ret == 1) {
-        WRN("Some models failed to be loaded, any data from these models will be ignored.");
+    if (session->flags & NC_SESSION_CLIENT_NOT_STRICT) {
+        WRN("Some models failed to be loaded, any data from these models (and any other unknown) will be ignored.");
     }
     return ret;
 }
@@ -838,8 +834,7 @@
             if (rpc_gen->has_data) {
                 rpc_act = rpc_gen->content.data;
             } else {
-                rpc_act = lyd_parse_mem(ctx, rpc_gen->content.xml_str,
-                                        LYD_XML, LYD_OPT_RPC | LYD_OPT_STRICT | parseroptions, NULL);
+                rpc_act = lyd_parse_mem(ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC | parseroptions, NULL);
                 if (!rpc_act) {
                     ERR("Failed to parse a generic RPC/action XML.");
                     return NULL;
@@ -864,7 +859,7 @@
             /* special treatment */
             data = lyd_parse_xml(ctx, &xml->child->child,
                                  LYD_OPT_DESTRUCT | (rpc->type == NC_RPC_GETCONFIG ? LYD_OPT_GETCONFIG : LYD_OPT_GET)
-                                 | LYD_OPT_STRICT | parseroptions);
+                                 | parseroptions);
             if (!data) {
                 ERR("Failed to parse <%s> reply.", (rpc->type == NC_RPC_GETCONFIG ? "get-config" : "get"));
                 return NULL;
@@ -906,8 +901,7 @@
         data_rpl->type = NC_RPL_DATA;
         if (!data) {
             data_rpl->data = lyd_parse_xml(ctx, &xml->child,
-                                           LYD_OPT_RPCREPLY | LYD_OPT_DESTRUCT | LYD_OPT_STRICT | parseroptions,
-                                           rpc_act, NULL);
+                                           LYD_OPT_RPCREPLY | LYD_OPT_DESTRUCT | parseroptions, rpc_act, NULL);
         } else {
             /* <get>, <get-config> */
             data_rpl->data = data;
@@ -1152,12 +1146,15 @@
         return NC_MSG_ERROR;
     }
     parseroptions &= ~(LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS);
+    if (!(session->flags & NC_SESSION_CLIENT_NOT_STRICT)) {
+        parseroptions &= LYD_OPT_STRICT;
+    }
     *reply = NULL;
 
     msgtype = get_msg(session, timeout, msgid, &xml);
 
     if ((msgtype == NC_MSG_REPLY) || (msgtype == NC_MSG_REPLY_ERR_MSGID)) {
-        *reply = parse_reply(session->ctx, xml, rpc, LYD_OPT_STRICT | parseroptions);
+        *reply = parse_reply(session->ctx, xml, rpc, parseroptions);
         lyxml_free(session->ctx, xml);
         if (!(*reply)) {
             return NC_MSG_ERROR;
@@ -1209,7 +1206,8 @@
         }
 
         /* notification body */
-        (*notif)->tree = lyd_parse_xml(session->ctx, &xml->child, LYD_OPT_NOTIF | LYD_OPT_STRICT | LYD_OPT_DESTRUCT, NULL);
+        (*notif)->tree = lyd_parse_xml(session->ctx, &xml->child, LYD_OPT_NOTIF | LYD_OPT_DESTRUCT
+                                       | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL);
         lyxml_free(session->ctx, xml);
         xml = NULL;
         if (!(*notif)->tree) {
@@ -1366,7 +1364,8 @@
         if (rpc_gen->has_data) {
             data = rpc_gen->content.data;
         } else {
-            data = lyd_parse_mem(session->ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC | LYD_OPT_STRICT, NULL);
+            data = lyd_parse_mem(session->ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC
+                                 | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL);
         }
         break;
 
@@ -1786,7 +1785,7 @@
         return NC_MSG_ERROR;
     }
 
-    if (lyd_validate(&data, LYD_OPT_RPC | LYD_OPT_STRICT, NULL)) {
+    if (lyd_validate(&data, LYD_OPT_RPC | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL)) {
         lyd_free(data);
         return NC_MSG_ERROR;
     }