Fix NetconfAccess not being able to fetch submodules

When I implemented SysrepoAccess, I ignored the submoduleRevision
argument in the "libyang missing schema callback" as Sysrepo seemed to
work just fine without supplying it. However, libnetconf needs it
because one can't supply both module name and submodule name to a
<get-schema> request. Now, if a submodule is being requested by libyang
from NetconfAccess, I pass the submodule name to libnetconf rather
than the module name.

Issue: https://tree.taiga.io/project/jktjkt-netconf-cli/issue/123
Change-Id: I0e5f6b82b1598ecc9f27732f450b1a204ee500f9
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index c1bd5dc..3d54443 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -76,10 +76,11 @@
 
 void NetconfAccess::datastoreInit()
 {
-    m_schema->registerModuleCallback([this](const char* moduleName, const char* revision, const char* submodule) {
+    m_schema->registerModuleCallback([this](const char* moduleName, const char* revision, const char* submodule, const char* submoduleRevision) {
         return fetchSchema(moduleName,
                            revision ? std::optional{revision} : std::nullopt,
-                           submodule ? std::optional{submodule} : std::nullopt);
+                           submodule ? std::optional{submodule} : std::nullopt,
+                           submoduleRevision ? std::optional{submoduleRevision} : std::nullopt);
     });
 
     for (const auto& it : listImplementedSchemas()) {
@@ -149,8 +150,14 @@
     m_session->discard();
 }
 
-std::string NetconfAccess::fetchSchema(const std::string_view module, const std::optional<std::string_view> revision, const std::optional<std::string_view>)
+std::string NetconfAccess::fetchSchema(const std::string_view module, const
+        std::optional<std::string_view> revision, const
+        std::optional<std::string_view> submodule, const
+        std::optional<std::string_view> submoduleRevision)
 {
+    if (submodule) {
+        return m_session->getSchema(*submodule, submoduleRevision);
+    }
     return m_session->getSchema(module, revision);
 }
 
diff --git a/src/netconf_access.hpp b/src/netconf_access.hpp
index 4c0e813..ccfffcc 100644
--- a/src/netconf_access.hpp
+++ b/src/netconf_access.hpp
@@ -44,7 +44,10 @@
     std::shared_ptr<Schema> schema() override;
 
 private:
-    std::string fetchSchema(const std::string_view module, const std::optional<std::string_view> revision, const std::optional<std::string_view>);
+    std::string fetchSchema(const std::string_view module, const
+            std::optional<std::string_view> revision, const
+            std::optional<std::string_view> submodule, const
+            std::optional<std::string_view> submoduleRevision);
     std::vector<std::string> listImplementedSchemas();
     void datastoreInit();
     void doEditFromDataNode(std::shared_ptr<libyang::Data_Node> dataNode);
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index f84bb91..eec6d6c 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -89,7 +89,10 @@
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
     }
-    m_schema->registerModuleCallback([this](const char* moduleName, const char* revision, const char* submodule) {
+
+    // If fetching a submodule, sysrepo::Session::get_schema will determine the revision from the main module.
+    // That's why submoduleRevision is ignored.
+    m_schema->registerModuleCallback([this](const char* moduleName, const char* revision, const char* submodule, [[maybe_unused]] const char* submoduleRevision) {
         return fetchSchema(moduleName, revision, submodule);
     });
 
@@ -199,7 +202,7 @@
 {
     std::string schema;
     try {
-        schema = m_session->get_schema(module, revision, submodule, SR_SCHEMA_YANG); // FIXME: maybe we should use get_submodule_schema for submodules?
+        schema = m_session->get_schema(module, revision, submodule, SR_SCHEMA_YANG);
     } catch (sysrepo::sysrepo_exception& ex) {
         reportErrors();
     }
diff --git a/src/yang_schema.cpp b/src/yang_schema.cpp
index 9868c63..5de3b9e 100644
--- a/src/yang_schema.cpp
+++ b/src/yang_schema.cpp
@@ -377,11 +377,11 @@
     m_context->get_module(moduleName.c_str())->feature_enable(featureName.c_str());
 }
 
-void YangSchema::registerModuleCallback(const std::function<std::string(const char*, const char*, const char*)>& clb)
+void YangSchema::registerModuleCallback(const std::function<std::string(const char*, const char*, const char*, const char*)>& clb)
 {
     auto lambda = [clb](const char* mod_name, const char* mod_revision, const char* submod_name, const char* submod_revision) {
         (void)submod_revision;
-        auto moduleSource = clb(mod_name, mod_revision, submod_name);
+        auto moduleSource = clb(mod_name, mod_revision, submod_name, submod_revision);
         if (moduleSource.empty()) {
             return libyang::Context::mod_missing_cb_return{LYS_IN_YANG, nullptr};
         }
diff --git a/src/yang_schema.hpp b/src/yang_schema.hpp
index 27452de..7fcd58c 100644
--- a/src/yang_schema.hpp
+++ b/src/yang_schema.hpp
@@ -45,7 +45,7 @@
     std::set<std::string> childNodes(const schemaPath_& path, const Recursion recursion) const override;
     std::set<std::string> moduleNodes(const module_& module, const Recursion recursion) const override;
 
-    void registerModuleCallback(const std::function<std::string(const char*, const char*, const char*)>& clb);
+    void registerModuleCallback(const std::function<std::string(const char*, const char*, const char*, const char*)>& clb);
 
     /** @short Loads a module called moduleName. */
     void loadModule(const std::string& moduleName);
diff --git a/tests/yang.cpp b/tests/yang.cpp
index 64bf08e..d519825 100644
--- a/tests/yang.cpp
+++ b/tests/yang.cpp
@@ -278,7 +278,7 @@
 {
     using namespace std::string_view_literals;
     YangSchema ys;
-    ys.registerModuleCallback([]([[maybe_unused]] auto modName, auto, auto) {
+    ys.registerModuleCallback([]([[maybe_unused]] auto modName, auto, auto, auto) {
         assert("example-schema"sv == modName);
         return example_schema;
     });