update: Add/delete prefix to the conf file

refs: #4303

Change-Id: I401885bf76be90a5076365eebc311275461813c4
diff --git a/src/nlsr.cpp b/src/nlsr.cpp
index 00f4d8e..6045935 100644
--- a/src/nlsr.cpp
+++ b/src/nlsr.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2018,  The University of Memphis,
+ * Copyright (c) 2014-2019,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -68,7 +68,8 @@
   , m_prefixUpdateProcessor(m_dispatcher,
                             m_nlsrFace,
                             m_namePrefixList,
-                            m_nlsrLsdb)
+                            m_nlsrLsdb,
+                            m_configFileName)
   , m_nfdRibCommandProcessor(m_dispatcher,
                              m_namePrefixList,
                              m_nlsrLsdb)
diff --git a/src/update/manager-base.cpp b/src/update/manager-base.cpp
index 071fc3a..f8ab6d1 100644
--- a/src/update/manager-base.cpp
+++ b/src/update/manager-base.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2018,  The University of Memphis,
+ * Copyright (c) 2014-2019,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -61,12 +61,35 @@
 
   // Only build a Name LSA if the added name is new
   if (m_namePrefixList.insert(castParams.getName())) {
-    NLSR_LOG_INFO("Advertising/Inserting name: " << castParams.getName() << "\n");
+    NLSR_LOG_INFO("Advertising name: " << castParams.getName() << "\n");
     m_lsdb.buildAndInstallOwnNameLsa();
+    if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
+      NLSR_LOG_INFO("Saving name to the configuration file");
+      if (afterAdvertise(castParams.getName()) == true) {
+        return done(ndn::nfd::ControlResponse(205, "OK").setBody(parameters.wireEncode()));
+      }
+      else {
+        return done(ndn::nfd::ControlResponse(406, "Failed to open configuration file.")
+                    .setBody(parameters.wireEncode()));
+      }
+    }
     return done(ndn::nfd::ControlResponse(200, "OK").setBody(parameters.wireEncode()));
   }
-
-  return done(ndn::nfd::ControlResponse(204, "Prefix is already advetised/inserted.").setBody(parameters.wireEncode()));
+  else {
+    if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
+      // Save an already advertised prefix
+      NLSR_LOG_INFO("Saving an already advertised name: " << castParams.getName() << "\n");
+      if (afterAdvertise(castParams.getName()) == true) {
+        return done(ndn::nfd::ControlResponse(205, "OK").setBody(parameters.wireEncode()));
+      }
+      else {
+        return done(ndn::nfd::ControlResponse(406, "Prefix is already Saved/Failed to open configuration file.")
+                    .setBody(parameters.wireEncode()));
+      }
+    }
+    return done(ndn::nfd::ControlResponse(204, "Prefix is already advertised/inserted.")
+                .setBody(parameters.wireEncode()));
+  }
 }
 
 void
@@ -82,10 +105,32 @@
   if (m_namePrefixList.remove(castParams.getName())) {
     NLSR_LOG_INFO("Withdrawing/Removing name: " << castParams.getName() << "\n");
     m_lsdb.buildAndInstallOwnNameLsa();
+    if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
+      if (afterWithdraw(castParams.getName()) == true) {
+        return done(ndn::nfd::ControlResponse(205, "OK").setBody(parameters.wireEncode()));
+      }
+      else {
+        return done(ndn::nfd::ControlResponse(406, "Failed to open configuration file.")
+                    .setBody(parameters.wireEncode()));
+      }
+    }
     return done(ndn::nfd::ControlResponse(200, "OK").setBody(parameters.wireEncode()));
   }
-
-  return done(ndn::nfd::ControlResponse(204, "Prefix is already withdrawn/removed.").setBody(parameters.wireEncode()));
+  else {
+    if (castParams.hasFlags() && castParams.getFlags() == PREFIX_FLAG) {
+      // Delete an already withdrawn prefix
+      NLSR_LOG_INFO("Deleting an already withdrawn name: " << castParams.getName() << "\n");
+      if (afterWithdraw(castParams.getName()) == true) {
+        return done(ndn::nfd::ControlResponse(205, "OK").setBody(parameters.wireEncode()));
+      }
+      else {
+        return done(ndn::nfd::ControlResponse(406, "Prefix is already deleted/Failed to open configuration file.")
+                    .setBody(parameters.wireEncode()));
+      }
+    }
+    return done(ndn::nfd::ControlResponse(204, "Prefix is already withdrawn/removed.")
+                .setBody(parameters.wireEncode()));
+  }
 }
 
 } // namespace update
diff --git a/src/update/manager-base.hpp b/src/update/manager-base.hpp
index 0dddbd6..4d279c7 100644
--- a/src/update/manager-base.hpp
+++ b/src/update/manager-base.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2017,  The University of Memphis,
+ * Copyright (c) 2014-2019,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -44,6 +44,8 @@
 
 namespace update {
 
+enum { PREFIX_FLAG = 1 };
+
 class ManagerBase : boost::noncopyable
 {
 public:
@@ -107,6 +109,8 @@
                      Lsdb& lsdb,
                      const std::string& module);
 
+  virtual ~CommandManagerBase() {}
+
   /*! \brief add desired name prefix to the advertised name prefix list
    *         or insert a prefix into the FIB if parameters is valid.
    */
@@ -125,6 +129,18 @@
                           const ndn::mgmt::ControlParameters& parameters,
                           const ndn::mgmt::CommandContinuation& done);
 
+  /*! \brief save an advertised prefix to the nlsr configuration file
+   *         returns bool from the overridden function while nullopt here
+   */
+  virtual ndn::optional<bool>
+  afterAdvertise(const ndn::Name& prefix) { return ndn::nullopt; }
+
+  /*! \brief save an advertised prefix to the nlsr configuration file
+   *         returns bool from the overridden function while nullopt here
+   */
+  virtual ndn::optional<bool>
+  afterWithdraw(const ndn::Name& prefix) { return ndn::nullopt; }
+
 protected:
   NamePrefixList& m_namePrefixList;
   Lsdb& m_lsdb;
diff --git a/src/update/prefix-update-commands.cpp b/src/update/prefix-update-commands.cpp
index 0ec2542..e783086 100644
--- a/src/update/prefix-update-commands.cpp
+++ b/src/update/prefix-update-commands.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2017,  The University of Memphis,
+ * Copyright (c) 2014-2019,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -29,6 +29,9 @@
 {
   m_requestValidator.required(ndn::nfd::CONTROL_PARAMETER_NAME);
   m_responseValidator.required(ndn::nfd::CONTROL_PARAMETER_NAME);
+
+  m_requestValidator.optional(ndn::nfd::CONTROL_PARAMETER_FLAGS);
+  m_responseValidator.optional(ndn::nfd::CONTROL_PARAMETER_FLAGS);
 }
 
 AdvertisePrefixCommand::AdvertisePrefixCommand()
@@ -36,6 +39,10 @@
 {
   m_requestValidator.required(ndn::nfd::CONTROL_PARAMETER_NAME);
   m_responseValidator.required(ndn::nfd::CONTROL_PARAMETER_NAME);
+
+  m_requestValidator.optional(ndn::nfd::CONTROL_PARAMETER_FLAGS);
+  m_responseValidator.optional(ndn::nfd::CONTROL_PARAMETER_FLAGS);
+
 }
 
 } // namespace update
diff --git a/src/update/prefix-update-processor.cpp b/src/update/prefix-update-processor.cpp
index 57bb579..3573ef0 100644
--- a/src/update/prefix-update-processor.cpp
+++ b/src/update/prefix-update-processor.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2018,  The University of Memphis,
+ * Copyright (c) 2014-2019,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -23,8 +23,9 @@
 #include "lsdb.hpp"
 #include "nlsr.hpp"
 #include <ndn-cxx/mgmt/nfd/control-response.hpp>
-#include <ndn-cxx/tag.hpp>
 #include <ndn-cxx/face.hpp>
+#include <boost/algorithm/string.hpp>
+#include <algorithm>
 
 namespace nlsr {
 namespace update {
@@ -52,9 +53,10 @@
 PrefixUpdateProcessor::PrefixUpdateProcessor(ndn::mgmt::Dispatcher& dispatcher,
                                              ndn::Face& face,
                                              NamePrefixList& namePrefixList,
-                                             Lsdb& lsdb)
+                                             Lsdb& lsdb, const std::string& configFileName)
   : CommandManagerBase(dispatcher, namePrefixList, lsdb, "prefix-update")
   , m_validator(std::make_unique<ndn::security::v2::CertificateFetcherDirectFetch>(face))
+  , m_configFileName(configFileName)
 {
   NLSR_LOG_DEBUG("Setting dispatcher to capture Interests for: "
     << ndn::Name(Nlsr::LOCALHOST_PREFIX).append("prefix-update"));
@@ -102,5 +104,90 @@
   m_validator.load(section, filename);
 }
 
+bool
+PrefixUpdateProcessor::checkForPrefixInFile(const std::string prefix)
+{
+  std::string line;
+  std::fstream fp(m_configFileName);
+  if (!fp.good() || !fp.is_open()) {
+    NLSR_LOG_ERROR("Failed to open configuration file for parsing");
+    return true;
+  }
+  while (!fp.eof()) {
+    getline(fp, line);
+    if (line == prefix) {
+      return true;
+    }
+  }
+  fp.close();
+  return false;
+}
+
+bool
+PrefixUpdateProcessor::addOrDeletePrefix(const ndn::Name& prefix, bool addPrefix)
+{
+  std::string value = " prefix " + prefix.toUri();;
+  std::string fileString;
+  std::string line;
+  std::string trimedLine;
+  std::fstream input(m_configFileName, input.in);
+  if (!input.good() || !input.is_open()) {
+    NLSR_LOG_ERROR("Failed to open configuration file for parsing");
+    return false;
+  }
+
+  if (addPrefix) {
+    //check if prefix already exist in the nlsr configuration file
+    if (checkForPrefixInFile(value)) {
+      NLSR_LOG_ERROR("Prefix already exists in the configuration file");
+      return false;
+    }
+    while (!input.eof()) {
+      getline(input, line);
+      if (!line.empty()) {
+        fileString.append(line + "\n");
+        if (line == "advertising") {
+          getline(input, line);
+          fileString.append(line + "\n" + value + "\n");
+        }
+      }
+    }
+  }
+  else {
+    if (!checkForPrefixInFile(value)) {
+      NLSR_LOG_ERROR("Prefix doesn't exists in the configuration file");
+      return false;
+    }
+    boost::trim(value);
+    while (!input.eof()) {
+      getline(input, line);
+      if (!line.empty()) {
+        std::string trimLine = line;
+        boost::trim(trimLine);
+        if (trimLine != value) {
+          fileString.append(line + "\n");
+        }
+      }
+    }
+  }
+  input.close();
+  std::ofstream output(m_configFileName);
+  output << fileString;
+  output.close();
+  return true;
+}
+
+ndn::optional<bool>
+PrefixUpdateProcessor::afterAdvertise(const ndn::Name& prefix) {
+
+  return addOrDeletePrefix(prefix, true);
+}
+
+ndn::optional<bool>
+PrefixUpdateProcessor::afterWithdraw(const ndn::Name& prefix) {
+
+  return addOrDeletePrefix(prefix, false);
+}
+
 } // namespace update
 } // namespace nlsr
diff --git a/src/update/prefix-update-processor.hpp b/src/update/prefix-update-processor.hpp
index a602497..4491448 100644
--- a/src/update/prefix-update-processor.hpp
+++ b/src/update/prefix-update-processor.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2017,  The University of Memphis,
+ * Copyright (c) 2014-2019,  The University of Memphis,
  *                           Regents of the University of California,
  *                           Arizona Board of Regents.
  *
@@ -24,15 +24,11 @@
 
 #include "manager-base.hpp"
 #include "prefix-update-commands.hpp"
-#include "test-access-control.hpp"
-
 #include <ndn-cxx/util/io.hpp>
 #include <ndn-cxx/security/key-chain.hpp>
-#include <ndn-cxx/security/v2/certificate-storage.hpp>
 #include <ndn-cxx/util/io.hpp>
-
 #include <boost/property_tree/ptree.hpp>
-#include <memory>
+#include <boost/property_tree/info_parser.hpp>
 
 namespace nlsr {
 
@@ -50,7 +46,7 @@
   PrefixUpdateProcessor(ndn::mgmt::Dispatcher& dispatcher,
                         ndn::Face& face,
                         NamePrefixList& namePrefixList,
-                        Lsdb& lsdb);
+                        Lsdb& lsdb, const std::string& configFileName);
 
   /*! \brief Load the validator's configuration from a section of a
    * configuration file.
@@ -66,6 +62,22 @@
   void
   loadValidator(ConfigSection section, const std::string& filename);
 
+  /*! \brief Add or delete an advertise or withdrawn prefix to the nlsr
+   * configuration file
+   */
+  bool
+  addOrDeletePrefix(const ndn::Name& prefix, bool addPrefix);
+
+  ndn::optional<bool>
+  afterAdvertise(const ndn::Name& prefix);
+
+  ndn::optional<bool>
+  afterWithdraw(const ndn::Name& prefix);
+
+  /*! \brief Check if a prefix exists in the nlsr configuration file */
+  bool
+  checkForPrefixInFile(const std::string prefix);
+
   ndn::security::ValidatorConfig&
   getValidator()
   {
@@ -84,6 +96,7 @@
 
 private:
   ndn::security::ValidatorConfig m_validator;
+  const std::string& m_configFileName;
 };
 
 } // namespace update