update requester and cmd line tool after testing cmd line tool

Change-Id: I301ac41a402ef3e808017aad9a79ddfe7117942d
diff --git a/tools/ndncert-client.cpp b/tools/ndncert-client.cpp
index d85c839..96064b6 100644
--- a/tools/ndncert-client.cpp
+++ b/tools/ndncert-client.cpp
@@ -19,14 +19,14 @@
  */
 
 #include "challenge-module.hpp"
-#include "requester.hpp"
 #include "protocol-detail/info.hpp"
-#include <ndn-cxx/security/verification-helpers.hpp>
+#include "requester.hpp"
 #include <boost/asio.hpp>
 #include <boost/program_options/options_description.hpp>
 #include <boost/program_options/parsers.hpp>
 #include <boost/program_options/variables_map.hpp>
 #include <iostream>
+#include <ndn-cxx/security/verification-helpers.hpp>
 #include <string>
 
 namespace ndn {
@@ -40,10 +40,8 @@
 runNew(CaProfile profile, Name identityName);
 static void
 runChallenge(const std::string& challengeType);
-static void
-startApplication(std::string configFilePath);
 
-int nStep;
+size_t nStep = 1;
 Face face;
 security::v2::KeyChain keyChain;
 shared_ptr<RequesterState> requesterState = nullptr;
@@ -69,7 +67,7 @@
 {
   std::vector<std::tuple<std::string, std::string>> results;
   for (const auto& r : requirement) {
-      results.emplace_back(r, "Please input: " + r);
+    results.emplace_back(r, "Please input: " + r);
   }
   captureParams(results);
   return results;
@@ -78,7 +76,8 @@
 static int
 captureValidityPeriod()
 {
-  std::cerr << "Step " << nStep++
+  std::cerr << "\n***************************************\n"
+            << "Step " << nStep++
             << ": Please type in your expected validity period of your certificate."
             << " Type the number of hours (168 for week, 730 for month, 8760 for year)."
             << " The CA may reject your application if your expected period is too long." << std::endl;
@@ -86,13 +85,9 @@
     std::string periodStr = "";
     getline(std::cin, periodStr);
     try {
-      int validityPeriod = std::stoi(periodStr);
-      if (validityPeriod < 0) {
-          BOOST_THROW_EXCEPTION(std::runtime_error(""));
-      }
-      return validityPeriod;
+      return std::stoul(periodStr);
     }
-    catch (const std::exception &e) {
+    catch (const std::exception& e) {
       std::cerr << "Your input is invalid. Try again: " << std::endl;
     }
   }
@@ -115,11 +110,14 @@
 {
   auto item = Requester::onCertFetchResponse(reply);
   if (item) {
-      keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
+    keyChain.addCertificate(keyChain.getPib().getIdentity(item->getIdentity()).getKey(item->getKeyName()), *item);
   }
-  std::cerr << "Step " << nStep++
-            << ": DONE! Certificate has already been installed to local keychain\n"
-            << "Certificate Name: " << reply.getName().toUri() << std::endl;
+  std::cerr << "\n***************************************\n"
+            << "Step " << nStep++
+            << ": DONE\nCertificate with Name: " << reply.getName().toUri()
+            << "has already been installed to your local keychain" << std::endl
+            << "Exit now";
+  face.getIoService().stop();
 }
 
 static void
@@ -127,12 +125,13 @@
 {
   try {
     Requester::onChallengeResponse(*requesterState, reply);
-  } catch (const std::exception& e) {
+  }
+  catch (const std::exception& e) {
     std::cerr << "Error when decoding challenge step: " << e.what() << std::endl;
     exit(1);
   }
   if (requesterState->m_status == Status::SUCCESS) {
-    std::cerr << "Certificate has already been issued, downloading certificate... \n";
+    std::cerr << "Certificate has already been issued, downloading certificate..." << std::endl;
     face.expressInterest(*Requester::genCertFetchInterest(*requesterState), bind(&certFetchCb, _2),
                          bind(&onNackCb), bind(&timeoutCb));
     return;
@@ -146,39 +145,43 @@
 {
   std::list<std::string> challengeList;
   try {
-      challengeList = Requester::onNewRenewRevokeResponse(*requesterState, reply);
-  } catch (const std::exception& e) {
+    challengeList = Requester::onNewRenewRevokeResponse(*requesterState, reply);
+  }
+  catch (const std::exception& e) {
     std::cerr << "Error on decoding NEW step reply because: " << e.what() << std::endl;
     exit(1);
   }
 
-  int challengeIndex = 0;
+  size_t challengeIndex = 0;
   if (challengeList.size() < 1) {
     std::cerr << "There is no available challenge provided by the CA. Exit" << std::endl;
     exit(1);
   }
   else if (challengeList.size() > 1) {
-    int count = 0;
+    std::cerr << "\n***************************************\n"
+              << "Step " << nStep++
+              << ": CHALLENGE SELECTION" << std::endl;
+    size_t count = 0;
     std::string choice = "";
-    std::cerr << "Step " << nStep++ << ": Please type in the challenge index that you want to perform\n";
-    count = 0;
     for (auto item : challengeList) {
-      std::cerr << "\t" << count++ << " : " << item << std::endl;
+      std::cerr << "> Index: " << count++ << std::endl
+                << ">> Challenge:" << item << std::endl;
     }
+    std::cerr << "Please type in the challenge index that you want to perform:" << std::endl;
     while (true) {
-        getline(std::cin, choice);
-        try {
-            challengeIndex = std::stoi(choice);
-        }
-        catch (const std::exception &e) {
-            std::cerr << "Your input is not valid. Try again:" << std::endl;
-            continue;
-        }
-        if (challengeIndex < 0 || challengeIndex >= count) {
-            std::cerr << "Your input index is out of range. Try again:" << std::endl;
-            continue;
-        }
-        break;
+      getline(std::cin, choice);
+      try {
+        challengeIndex = std::stoul(choice);
+      }
+      catch (const std::exception& e) {
+        std::cerr << "Your input is not valid. Try again:" << std::endl;
+        continue;
+      }
+      if (challengeIndex >= count) {
+        std::cerr << "Your input index is out of range. Try again:" << std::endl;
+        continue;
+      }
+      break;
     }
   }
   auto it = challengeList.begin();
@@ -195,24 +198,26 @@
 }
 
 static void
-InfoCb(const Data& reply)
+InfoCb(const Data& reply, const Name& certFullName)
 {
-  CaProfile profile;
+  boost::optional<CaProfile> profile;
   try {
-    auto profileOpt = Requester::onCaProfileResponse(reply);
-    if (!profileOpt) {
-        BOOST_THROW_EXCEPTION(std::runtime_error("Invalid reply"));
+    if (certFullName.empty()) {
+      profile = Requester::onCaProfileResponse(reply);
     }
-    profile = *profileOpt;
-  } catch(const std::exception& e) {
-      std::cerr << "The fetched CA information cannot be used because: "<< e.what() << std::endl;
-      return;
+    else {
+      profile = Requester::onCaProfileResponseAfterRedirection(reply, certFullName);
+    }
+  }
+  catch (const std::exception& e) {
+    std::cerr << "The fetched CA information cannot be used because: " << e.what() << std::endl;
+    return;
   }
 
-  std::cerr << "Will use a new trust anchor, please double check the identity info: \n"
+  std::cerr << "Will use a new trust anchor, please double check the identity info:" << std::endl
             << "This trust anchor information is signed by " << reply.getSignature().getKeyLocator()
             << std::endl
-            << "The certificate is " << profile.m_cert << std::endl
+            << "The certificate is " << profile->m_cert << std::endl
             << "Do you trust the information? Type in YES or NO" << std::endl;
 
   std::string answer;
@@ -220,7 +225,7 @@
   boost::algorithm::to_lower(answer);
   if (answer == "yes") {
     std::cerr << "You answered YES: new CA will be used" << std::endl;
-    runProbe(profile);
+    runProbe(*profile);
     // client.getClientConf().save(std::string(SYSCONFDIR) + "/ndncert/client.conf");
   }
   else {
@@ -235,38 +240,45 @@
   std::vector<Name> names;
   std::vector<Name> redirects;
   Requester::onProbeResponse(reply, profile, names, redirects);
-  int count = 0;
-  std::cerr << "Here is CA's suggested names: " << std::endl;
+  size_t count = 0;
+  std::cerr << "\n***************************************\n"
+            << "Step " << nStep++
+            << ": You can either select one of the following names suggested by the CA: " << std::endl;
   for (const auto& name : names) {
-      std::cerr << count ++ << ": " << name.toUri() << std::endl;
+    std::cerr << "> Index: " << count++ << std::endl
+              << ">> Suggested name: " << name.toUri() << std::endl;
   }
-  std::cerr << "Here is CA's suggested redirects to other CAs: " << std::endl;
+  std::cerr << "\nOr choose another trusted CA suggested by the CA: " << std::endl;
   for (const auto& redirect : redirects) {
-      std::cerr << count ++ << ": " << redirect.toUri() << std::endl;
+    std::cerr << "> Index: " << count++ << std::endl
+              << ">> Suggested CA: " << security::v2::extractIdentityFromCertName(redirect.getPrefix(-1)) << std::endl;
   }
-  int index;
+  std::cerr << "Please type in the index of your choice:" << std::endl;
+  size_t index = 0;
   try {
     std::string input;
     getline(std::cin, input);
-    index = std::stoi(input);
+    index = std::stoul(input);
   }
   catch (const std::exception& e) {
     std::cerr << "Your input is Invalid. Exit" << std::endl;
     exit(0);
   }
-  if (index < 0 || index >= names.size() + redirects.size()) {
+  if (index >= names.size() + redirects.size()) {
     std::cerr << "Your input is not an existing index. Exit" << std::endl;
     return;
   }
   if (index < names.size()) {
-      //names
-      std::cerr << "You selected name: " << names[index].toUri() << std::endl;
-      runNew(profile, names[index]);
-  } else {
-      //redirects
-      std::cerr << "You selected redirects with certificate: " << redirects[index - names.size()].toUri() << std::endl;
-      face.expressInterest(*Requester::genCaProfileInterest(redirects[index - names.size()]),
-                           bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
+    //names
+    std::cerr << "You selected name: " << names[index].toUri() << std::endl;
+    runNew(profile, names[index]);
+  }
+  else {
+    //redirects
+    auto redirectedCaName = redirects[index - names.size()];
+    std::cerr << "You selected redirects with certificate: " << redirectedCaName.getPrefix(-1).toUri() << std::endl;
+    face.expressInterest(*Requester::genCaProfileInterest(redirects[index - names.size()]),
+                         bind(&InfoCb, _2, redirectedCaName), bind(&onNackCb), bind(&timeoutCb));
   }
 }
 
@@ -275,45 +287,44 @@
 {
   RequesterCaCache caCache;
   try {
-      caCache.load(configFilePath);
+    caCache.load(configFilePath);
   }
   catch (const std::exception& e) {
     std::cerr << "Cannot load the configuration file: " << e.what() << std::endl;
     exit(1);
   }
-  int count = 0;
+  size_t count = 0;
+  std::cerr << "***************************************\n"
+            << "Step " << nStep++ << ": CA SELECTION" << std::endl;
   for (auto item : caCache.m_caItems) {
-    std::cerr << "***************************************\n"
-              << "Index: " << count++ << "\n"
-              << "CA prefix:" << item.m_caPrefix << "\n"
-              << "Introduction: " << item.m_caInfo << "\n"
-              << "***************************************\n";
+    std::cerr << "> Index: " << count++ << std::endl
+              << ">> CA prefix:" << item.m_caPrefix << std::endl
+              << ">> Introduction: " << item.m_caInfo << std::endl;
   }
-  std::cerr << "Step "
-            << nStep++ << ": Please type in the CA INDEX that you want to apply"
-            << " or type in NONE if your expected CA is not in the list\n";
+  std::cerr << "Please type in the CA's index that you want to apply or type in NONE if your expected CA is not in the list:\n";
 
   std::string caIndexS, caIndexSLower;
   getline(std::cin, caIndexS);
   caIndexSLower = caIndexS;
   boost::algorithm::to_lower(caIndexSLower);
   if (caIndexSLower == "none") {
-    std::cerr << "Step " << nStep << ": Please type in the CA Name\n";
+    std::cerr << "\n***************************************\n"
+              << "Step " << nStep << ": ADD NEW CA\nPlease type in the CA's Name:" << std::endl;
     std::string expectedCAName;
     getline(std::cin, expectedCAName);
     face.expressInterest(*Requester::genCaProfileInterest(Name(expectedCAName)),
-                         bind(&InfoCb, _2), bind(&onNackCb), bind(&timeoutCb));
+                         bind(&InfoCb, _2, Name()), bind(&onNackCb), bind(&timeoutCb));
   }
   else {
-    int caIndex;
+    size_t caIndex;
     try {
-      caIndex = std::stoi(caIndexS);
+      caIndex = std::stoul(caIndexS);
     }
     catch (const std::exception& e) {
       std::cerr << "Your input is neither NONE nor a valid index. Exit" << std::endl;
       return;
     }
-    if (caIndex < 0 || caIndex >= count) {
+    if (caIndex >= count) {
       std::cerr << "Your input is not an existing index. Exit" << std::endl;
       return;
     }
@@ -324,48 +335,55 @@
   }
 }
 
-static void runProbe(CaProfile profile)
+static void
+runProbe(CaProfile profile)
 {
-    std::cerr << "Do you have the identity name already? Type in YES or NO" << std::endl;
-    bool validAnswer = false;
-    while (!validAnswer) {
-        std::string answer;
-        getline(std::cin, answer);
-        boost::algorithm::to_lower(answer);
-        if (answer == "yes") {
-            validAnswer = true;
-            std::cerr << "You answered YES: " << std::endl;
-            std::cerr << "Step " << nStep++ << ": Please type in the full identity name you want to get (with CA prefix)\n";
-            std::string identityNameStr;
-            getline(std::cin, identityNameStr);
-            runNew(profile, Name(identityNameStr));
-        } else if (answer == "no") {
-            validAnswer = true;
-            std::cerr << "You answered NO: new CA will not be used" << std::endl;
-            std::cerr << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
-            auto capturedParams = captureParams(profile.m_probeParameterKeys);
-            face.expressInterest(*Requester::genProbeInterest(profile, std::move(capturedParams)),
-                                 bind(&probeCb, _2, profile), bind(&onNackCb), bind(&timeoutCb));
-        } else {
-            std::cerr << "Invalid answer. Type in YES or NO" << std::endl;
-        }
+  std::cerr << "\n***************************************\n"
+            << "Step " << nStep++ << ": Do you have the identity name already? Type in YES or NO" << std::endl;
+  bool validAnswer = false;
+  while (!validAnswer) {
+    std::string answer;
+    getline(std::cin, answer);
+    boost::algorithm::to_lower(answer);
+    if (answer == "yes") {
+      validAnswer = true;
+      std::cerr << "You answered YES" << std::endl;
+      std::cerr << "\n***************************************\n"
+                << "Step " << nStep++
+                << ": Please type in the full identity name you want to get (with CA prefix):" << std::endl;
+      std::string identityNameStr;
+      getline(std::cin, identityNameStr);
+      runNew(profile, Name(identityNameStr));
     }
+    else if (answer == "no") {
+      validAnswer = true;
+      std::cerr << "You answered NO" << std::endl;
+      std::cerr << "\n***************************************\n"
+                << "Step " << nStep++ << ": Please provide information for name assignment" << std::endl;
+      auto capturedParams = captureParams(profile.m_probeParameterKeys);
+      face.expressInterest(*Requester::genProbeInterest(profile, std::move(capturedParams)),
+                           bind(&probeCb, _2, profile), bind(&onNackCb), bind(&timeoutCb));
+    }
+    else {
+      std::cerr << "Invalid answer. Type in YES or NO" << std::endl;
+    }
+  }
 }
 
 static void
 runNew(CaProfile profile, Name identityName)
 {
-    int validityPeriod = captureValidityPeriod();
-    auto now = time::system_clock::now();
-    std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
-    requesterState = make_shared<RequesterState>(keyChain, profile, RequestType::NEW);
-    auto interest = Requester::genNewInterest(*requesterState, identityName, now, now + time::hours(validityPeriod));
-    if (interest != nullptr) {
-        face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
-    }
-    else {
-        std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
-    }
+  int validityPeriod = captureValidityPeriod();
+  auto now = time::system_clock::now();
+  std::cerr << "The validity period of your certificate will be: " << validityPeriod << " hours" << std::endl;
+  requesterState = make_shared<RequesterState>(keyChain, profile, RequestType::NEW);
+  auto interest = Requester::genNewInterest(*requesterState, identityName, now, now + time::hours(validityPeriod));
+  if (interest != nullptr) {
+    face.expressInterest(*interest, bind(&newCb, _2), bind(&onNackCb), bind(&timeoutCb));
+  }
+  else {
+    std::cerr << "Cannot generate the Interest for NEW step. Exit" << std::endl;
+  }
 }
 
 static void
@@ -373,19 +391,13 @@
 {
   auto requirement = Requester::selectOrContinueChallenge(*requesterState, challengeType);
   if (requirement.size() > 0) {
-      std::cerr << "Step " << nStep++ << ": Please provide parameters used for Identity Verification Challenge\n";
-      captureParams(requirement);
+    std::cerr << "\n***************************************\n"
+              << "Step " << nStep
+              << ": Please provide parameters used for Identity Verification Challenge" << std::endl;
+    captureParams(requirement);
   }
   face.expressInterest(*Requester::genChallengeInterest(*requesterState, std::move(requirement)),
-                         bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
-
-}
-
-
-static void
-startApplication(std::string configFilePath)
-{
-  selectCaProfile(configFilePath);
+                       bind(&challengeCb, _2), bind(&onNackCb), bind(&timeoutCb));
 }
 
 static void
@@ -421,9 +433,7 @@
   namespace po = boost::program_options;
   std::string configFilePath = std::string(SYSCONFDIR) + "/ndncert/client.conf";
   po::options_description description("General Usage\n ndncert-client [-h] [-c] [-v]\n");
-  description.add_options()
-      ("help,h", "produce help message")
-      ("config-file,c", po::value<std::string>(&configFilePath), "configuration file name");
+  description.add_options()("help,h", "produce help message")("config-file,c", po::value<std::string>(&configFilePath), "configuration file name");
   po::positional_options_description p;
 
   po::variables_map vm;
@@ -439,7 +449,7 @@
     std::cerr << description << std::endl;
     return 0;
   }
-  startApplication(configFilePath);
+  selectCaProfile(configFilePath);
   face.processEvents();
   return 0;
 }