major change: Add security support & Adjust GUI

Change-Id: I7abef37169dec1ef4b68e760dee5214c147c1915
diff --git a/src/contact-manager.cpp b/src/contact-manager.cpp
index f755965..7be5017 100644
--- a/src/contact-manager.cpp
+++ b/src/contact-manager.cpp
@@ -12,38 +12,38 @@
 #pragma clang diagnostic ignored "-Wtautological-compare"
 #endif
 
-
 #include "contact-manager.h"
+#include <QStringList>
 
 #ifndef Q_MOC_RUN
-#include <ndn-cpp-dev/face.hpp>
-#include <ndn-cpp-dev/security/signature-sha256-with-rsa.hpp>
-
-#ifndef WITH_SECURITY
-#include <ndn-cpp-dev/security/validator-null.hpp>
-#else
+#include <ndn-cpp-dev/util/crypto.hpp>
+#include <ndn-cpp-dev/util/io.hpp>
+#include <ndn-cpp-dev/security/sec-rule-relative.hpp>
 #include <ndn-cpp-dev/security/validator-regex.hpp>
 #include <cryptopp/base64.h>
-#include <ndn-cpp-dev/security/sec-rule-relative.hpp>
-#endif
-
-#include "endorse-collection.pb.h"
+#include <cryptopp/files.h>
+#include <cryptopp/sha.h>
+#include <boost/asio.hpp>
+#include <boost/tokenizer.hpp>
+#include <boost/filesystem.hpp>
 #include "logging.h"
 #endif
 
 using namespace ndn;
 using namespace std;
+namespace fs = boost::filesystem;
 
-INIT_LOGGER("ContactManager");
+INIT_LOGGER("chronos.ContactManager");
 
 namespace chronos{
 
+static const uint8_t DNS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
+
 ContactManager::ContactManager(shared_ptr<Face> face,
                                QObject* parent)
   : QObject(parent)
-  , m_contactStorage(new ContactStorage())
-  , m_dnsStorage(new DnsStorage())
   , m_face(face)
+  , m_dnsListenerId(0)
 {
   initializeSecurity();
 }
@@ -51,108 +51,37 @@
 ContactManager::~ContactManager()
 {}
 
+// private methods
 void
 ContactManager::initializeSecurity()
 {
-  
-#ifndef WITH_SECURITY
-  
-  m_keyChain = make_shared<KeyChain>();
-  m_validator = make_shared<ValidatorNull>();
+  fs::path anchorPath = fs::path(getenv("HOME")) / ".chronos" / "anchor.cert";
+  shared_ptr<IdentityCertificate> anchor = io::load<IdentityCertificate>(anchorPath.c_str());
 
-#else
-
-  shared_ptr<SecPolicySimple> policy = make_shared<SecPolicySimple>();
-  m_verifier = make_shared<Verifier>(policy);
-  m_verifier->setFace(m_face);
-
-  policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><ENDORSED>",
-                                                                 "^([^<KEY>]*)<KEY>(<>*)[<ksk-.*><dsk-.*>]<ID-CERT>$",
-                                                                 "==", "\\1", "\\1\\2", true));
-  policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
-                                                                 "^([^<KEY>]*)<KEY>(<>*)[<ksk-.*><dsk-.*>]<ID-CERT>$",
-                                                                 "==", "\\1", "\\1\\2", true));
-  policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<PROFILE-CERT>]*)<PROFILE-CERT>",
-                                                                 "^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$", 
-                                                                 "==", "\\1", "\\1\\2", true));
-  policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
-                                                                 "^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>$",
-                                                                 ">", "\\1\\2", "\\1", true));
-  policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
-                                                                 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
-                                                                 "==", "\\1", "\\1\\2", true));
-  policy->addVerificationPolicyRule(make_shared<SecRuleRelative>("^(<>*)$", 
-                                                                 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
-                                                                 ">", "\\1", "\\1\\2", true));
-  
-
-  policy->addSigningPolicyRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
-                                                            "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>",
-                                                            "==", "\\1", "\\1\\2", true));
-
-
-  const string TrustAnchor("BIICqgOyEIWlKzDI2xX2hdq5Azheu9IVyewcV4uM7ylfh67Y8MIxF3tDCTx5JgEn\
-HYMuCaYQm6XuaXTlVfDdWff/K7Xebq8IgGxjNBeU9eMf7Gy9iIMrRAOdBG0dBHmo\
-67biGs8F+P1oh1FwKu/FN1AE9vh8HSOJ94PWmjO+6PvITFIXuI3QbcCz8rhvbsfb\
-5X/DmfbJ8n8c4X3nVxrBm6fd4z8kOFOvvhgJImvqsow69Uy+38m8gJrmrcWMoPBJ\
-WsNLcEriZCt/Dlg7EqqVrIn6ukylKCvVrxA9vm/cEB74J/N+T0JyMRDnTLm17gpq\
-Gd75rhj+bLmpOMOBT7Nb27wUKq8gcXzeAADy+p1uZG4A+p1LRVkA+vVrc2stMTM4\
-MzMyNTcyMAD6vUlELUNFUlQA+q39PgurHgAAAaID4gKF5vjua9EIr3/Fn8k1AdSc\
-nEryjVDW3ikvYoSwjK7egTkAArq1BSc+C6sdAAHiAery+p1uZG4A+p1LRVkA+vVr\
-c2stMTM4MzMyNTcyMAD6vUlELUNFUlQAAAAAAAGaFr0wggFjMCIYDzIwMTMxMTAx\
-MTcxMTIyWhgPMjAxNDExMDExNzExMjJaMBkwFwYDVQQpExBORE4gVGVzdGJlZCBS\
-b290MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA06x+elwzWCHa4I3b\
-yrYCMAIVxQpRVLuOXp0h+BS+5GNgMVPi7+40o4zSJG+kiU8CIH1mtj8RQAzBX9hF\
-I5VAyOC8nS8D8YOfBwt2yRDZPgt1E5PpyYUBiDYuq/zmJDL8xjxAlxrMzVOqD/uj\
-/vkkcBM/T1t9Q6p1CpRyq+GMRbV4EAHvH7MFb6bDrH9t8DHEg7NPUCaSQBrd7PvL\
-72P+QdiNH9zs/EiVzAkeMG4iniSXLuYM3z0gMqqcyUUUr6r1F9IBmDO+Kp97nZh8\
-VCL+cnIEwyzAFAupQH5GoXUWGiee8oKWwH2vGHX7u6sWZsCp15NMSG3OC4jUIZOE\
-iVUF1QIBEQAA");
-
-  string decoded;
-  CryptoPP::StringSource ss(reinterpret_cast<const unsigned char *>(TrustAnchor.c_str()), 
-                            TrustAnchor.size(), 
-                            true,
-                            new CryptoPP::Base64Decoder(new CryptoPP::StringSink(decoded)));
-  Data data;
-  data.wireDecode(Block(reinterpret_cast<const uint8_t*>(decoded.c_str()), decoded.size()));
-  shared_ptr<IdentityCertificate> anchor = make_shared<IdentityCertificate>(data);
-  policy->addTrustAnchor(anchor);  
-#endif
-}
-
-
-void
-ContactManager::fetchSelfEndorseCertificate(const ndn::Name& identity)
-{
-  Name interestName = identity;
-  interestName.append("DNS").append("PROFILE");
-  
-  Interest interest(interestName);
-  interest.setMustBeFresh(true);
-
-  OnDataValidated onValidated = bind(&ContactManager::onDnsSelfEndorseCertValidated, this, _1, identity);
-  OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsSelfEndorseCertValidationFailed, this, _1, identity);
-  TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsSelfEndorseCertTimeoutNotify, this, identity);
-
-  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
-}
-
-void
-ContactManager::onDnsSelfEndorseCertValidated(const shared_ptr<const Data>& data, 
-                                              const Name& identity)
-{
-  try{
-    Data plainData;
-    plainData.wireDecode(data->getContent().blockFromValue());
-    EndorseCertificate selfEndorseCertificate(plainData);
-    if(Validator::verifySignature(plainData, plainData.getSignature(), selfEndorseCertificate.getPublicKeyInfo()))
-      emit contactFetched(selfEndorseCertificate); 
-    else
-      emit contactFetchFailed(identity);
-  }catch(...){
-    emit contactFetchFailed (identity);
-  }
+  shared_ptr<ValidatorRegex> validator = make_shared<ValidatorRegex>(m_face);
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><ENDORSED>",
+                                                                  "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
+                                                                  "==", "\\1", "\\1\\2", true));
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><><ENDORSEE>",
+                                                                  "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
+                                                                  "==", "\\1", "\\1\\2", true));
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><PROFILE>",
+                                                                  "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
+                                                                  "==", "\\1", "\\1\\2", true));
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<PROFILE-CERT>]*)<PROFILE-CERT>",
+                                                                  "^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$", 
+                                                                  "==", "\\1", "\\1\\2", true));
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
+                                                                  "^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>$",
+                                                                  ">", "\\1\\2", "\\1", true));
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
+                                                                  "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
+                                                                  "==", "\\1", "\\1\\2", true));
+  validator->addDataVerificationRule(make_shared<SecRuleRelative>("^(<>*)$", 
+                                                                  "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
+                                                                  ">", "\\1", "\\1\\2", true));
+  validator->addTrustAnchor(anchor);
+  m_validator = validator;
 }
 
 void
@@ -167,254 +96,799 @@
 
   OnDataValidated onValidated = bind(&ContactManager::onDnsCollectEndorseValidated, this, _1, identity);
   OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsCollectEndorseValidationFailed, this, _1, identity);
-  TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsCollectEndorseTimeoutNotify, this, identity);
+  TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsCollectEndorseTimeoutNotify, this, _1, identity);
 
-  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
+  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
 }
 
 void
-ContactManager::fetchKey(const Name& certName)
+ContactManager::fetchEndorseCertificateInternal(const Name& identity, int certIndex)
 {
-  Name interestName = certName;
-  
+  shared_ptr<EndorseCollection> endorseCollection = m_bufferedContacts[identity].m_endorseCollection;
+
+  if(certIndex >= endorseCollection->endorsement_size())
+    prepareEndorseInfo(identity);
+
+  Name interestName(endorseCollection->endorsement(certIndex).certname());
+
   Interest interest(interestName);
   interest.setInterestLifetime(1000);
   interest.setMustBeFresh(true);
 
-  OnDataValidated onValidated = bind(&ContactManager::onKeyValidated, this, _1, certName);
-  OnDataValidationFailed onValidationFailed = bind(&ContactManager::onKeyValidationFailed, this, _1, certName);
-  TimeoutNotify timeoutNotify = bind(&ContactManager::onKeyTimeoutNotify, this, certName);
-
-  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
+  m_face->expressInterest(interest,
+                          bind(&ContactManager::onEndorseCertificateInternal, 
+                               this, _1, _2, identity, certIndex,
+                               endorseCollection->endorsement(certIndex).hash()),
+                          bind(&ContactManager::onEndorseCertificateInternalTimeout,
+                               this, _1, identity, certIndex));
 }
 
 void
-ContactManager::onKeyValidated(const shared_ptr<const Data>& data, const Name& identity)
+ContactManager::prepareEndorseInfo(const Name& identity)
 {
-  IdentityCertificate identityCertificate(*data);
-  Profile profile(identityCertificate);
+  // _LOG_DEBUG("prepareEndorseInfo");
+  const Profile& profile = m_bufferedContacts[identity].m_selfEndorseCert->getProfile();
 
-  try{
-    EndorseCertificate endorseCertificate(identityCertificate, profile);
-    m_keyChain->sign(endorseCertificate);
-    emit contactKeyFetched (endorseCertificate); 
-  }catch(...){
-    return;
+  shared_ptr<EndorseInfo> endorseInfo = make_shared<EndorseInfo>();
+  m_bufferedContacts[identity].m_endorseInfo = endorseInfo;
+
+  Profile::const_iterator pIt  = profile.begin();
+  Profile::const_iterator pEnd = profile.end();
+
+  map<string, int> endorseCount;
+  for(; pIt != pEnd; pIt++)
+    {
+      // _LOG_DEBUG("prepareEndorseInfo: profile[" << pIt->first << "]: " << pIt->second);
+      endorseCount[pIt->first] = 0;
+    }
+
+  int endorseCertCount = 0;
+
+  vector<shared_ptr<EndorseCertificate> >::const_iterator cIt  = m_bufferedContacts[identity].m_endorseCertList.begin();
+  vector<shared_ptr<EndorseCertificate> >::const_iterator cEnd = m_bufferedContacts[identity].m_endorseCertList.end();
+
+  for(; cIt != cEnd; cIt++, endorseCertCount++)
+    {
+      shared_ptr<Contact> contact = getContact((*cIt)->getSigner().getPrefix(-1));
+      if(!static_cast<bool>(contact))
+        continue;
+      
+      if(!contact->isIntroducer() 
+         || !contact->canBeTrustedFor(profile.getIdentityName()))
+        continue;
+
+      if(!Validator::verifySignature(**cIt, contact->getPublicKey()))
+        continue;
+
+      const Profile& tmpProfile = (*cIt)->getProfile();
+      if(tmpProfile != profile)
+        continue;
+
+      const vector<string>& endorseList = (*cIt)->getEndorseList();
+      vector<string>::const_iterator eIt = endorseList.begin();
+      for(; eIt != endorseList.end(); eIt++)
+        endorseCount[*eIt] += 1;
+    }
+
+  pIt  = profile.begin();
+  pEnd = profile.end();
+  for(; pIt != pEnd; pIt++)
+    {
+      EndorseInfo::Endorsement* endorsement = endorseInfo->add_endorsement();
+      endorsement->set_type(pIt->first);
+      endorsement->set_value(pIt->second);
+      stringstream ss;
+      ss << endorseCount[pIt->first] << "/" << endorseCertCount;
+      endorsement->set_endorse(ss.str());
+    }
+
+  emit contactEndorseInfoReady (*endorseInfo);
+}
+
+void
+ContactManager::onDnsSelfEndorseCertValidated(const shared_ptr<const Data>& data, 
+                                              const Name& identity)
+{
+  try
+    {
+      Data plainData;
+      plainData.wireDecode(data->getContent().blockFromValue());
+      shared_ptr<EndorseCertificate> selfEndorseCertificate = make_shared<EndorseCertificate>(boost::cref(plainData));
+      if(Validator::verifySignature(plainData, selfEndorseCertificate->getPublicKeyInfo()))
+        {
+          m_bufferedContacts[identity].m_selfEndorseCert = selfEndorseCertificate;
+          fetchCollectEndorse(identity);
+        }
+      else
+        emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
+    }
+  catch(Block::Error& e)
+    {
+      emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
+    }
+  catch(Data::Error& e)
+    {
+      emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
+    }
+  catch(EndorseCertificate::Error& e)
+    {
+      emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
+    }
+}
+
+void
+ContactManager::onDnsSelfEndorseCertValidationFailed(const shared_ptr<const Data>& data, 
+                                                     const Name& identity)
+{
+  // If we cannot validate the Self-Endorse-Certificate, we may retry or fetch id-cert,
+  // but let's stay with failure for now.
+  emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
+}
+
+void
+ContactManager::onDnsSelfEndorseCertTimeoutNotify(const Interest& interest,
+                                                  const Name& identity)
+{
+  // If we cannot validate the Self-Endorse-Certificate, we may retry or fetch id-cert,
+  // but let's stay with failure for now.
+  emit contactInfoFetchFailed(QString::fromStdString(identity.toUri()));
+}
+
+void
+ContactManager::onDnsCollectEndorseValidated(const shared_ptr<const Data>& data, 
+                                             const Name& identity)
+{
+  shared_ptr<EndorseCollection> endorseCollection = make_shared<EndorseCollection>();
+  if(!endorseCollection->ParseFromArray(data->getContent().value(), data->getContent().value_size()))
+    {
+      m_bufferedContacts[identity].m_endorseCollection = endorseCollection;
+      fetchEndorseCertificateInternal(identity, 0);
+    }
+  else
+    prepareEndorseInfo(identity);
+}
+
+void
+ContactManager::onDnsCollectEndorseValidationFailed(const shared_ptr<const Data>& data, 
+                                                    const Name& identity)
+{
+  prepareEndorseInfo(identity);
+}
+
+void
+ContactManager::onDnsCollectEndorseTimeoutNotify(const Interest& interest,
+                                                 const Name& identity)
+{
+  // _LOG_DEBUG("onDnsCollectEndorseTimeoutNotify: " << interest.getName());
+  prepareEndorseInfo(identity);
+}
+
+void
+ContactManager::onEndorseCertificateInternal(const Interest& interest,
+                                             Data& data, 
+                                             const Name& identity, 
+                                             int certIndex,
+                                             string hash)
+{
+  stringstream ss;
+  {  
+    using namespace CryptoPP;
+
+    SHA256 hash;
+    StringSource(data.wireEncode().wire(), data.wireEncode().size(), true,
+                 new HashFilter(hash, new FileSink(ss)));
+  }
+  
+  if(ss.str() == hash)
+    {
+      shared_ptr<EndorseCertificate> endorseCertificate = make_shared<EndorseCertificate>(boost::cref(data));
+      m_bufferedContacts[identity].m_endorseCertList.push_back(endorseCertificate);
+    }
+
+  fetchEndorseCertificateInternal(identity, certIndex+1);
+}
+
+void
+ContactManager::onEndorseCertificateInternalTimeout(const Interest& interest,
+                                                    const Name& identity, 
+                                                    int certIndex)
+{
+  fetchEndorseCertificateInternal(identity, certIndex+1);
+}
+
+void
+ContactManager::collectEndorsement()
+{
+  {
+    boost::recursive_mutex::scoped_lock lock(m_collectCountMutex);
+    m_collectCount = m_contactList.size();
+    
+    ContactList::iterator it  = m_contactList.begin();
+    ContactList::iterator end = m_contactList.end();
+
+    for(; it != end ; it++)
+      {
+        Name interestName = (*it)->getNameSpace();
+        interestName.append("DNS").append(m_identity.wireEncode()).append("ENDORSEE");
+        
+        Interest interest(interestName);
+        interest.setInterestLifetime(1000);
+        
+        OnDataValidated onValidated = bind(&ContactManager::onDnsEndorseeValidated, this, _1);
+        OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsEndorseeValidationFailed, this, _1);
+        TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsEndorseeTimeoutNotify, this, _1);
+        
+        sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
+      }
   }
 }
 
 void
-ContactManager::fetchIdCertificate(const Name& certName)
+ContactManager::onDnsEndorseeValidated(const shared_ptr<const Data>& data)
 {
-  Name interestName = certName;
-  
-  Interest interest(interestName);
-  interest.setInterestLifetime(1000);
-  interest.setMustBeFresh(true);
+  Data endorseData;
+  endorseData.wireDecode(data->getContent().blockFromValue());
 
-  OnDataValidated onValidated = bind(&ContactManager::onIdCertValidated, this, _1, certName);
-  OnDataValidationFailed onValidationFailed = bind(&ContactManager::onIdCertValidationFailed, this, _1, certName);
-  TimeoutNotify timeoutNotify = bind(&ContactManager::onIdCertTimeoutNotify, this, certName);
+  EndorseCertificate endorseCertificate(endorseData);
+  m_contactStorage->updateCollectEndorse(endorseCertificate);
 
-  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
+  decreaseCollectStatus();
 }
 
 void
-ContactManager::updateProfileData(const Name& identity)
+ContactManager::onDnsEndorseeValidationFailed(const shared_ptr<const Data>& data)
 {
-  // Get current profile;
-  shared_ptr<Profile> newProfile = m_contactStorage->getSelfProfile(identity);
-  if(!static_cast<bool>(newProfile))
-    return;
-
-  shared_ptr<EndorseCertificate> newEndorseCertificate = getSignedSelfEndorseCertificate(identity, *newProfile);
-
-  if(!static_cast<bool>(newEndorseCertificate))
-    return;
-
-  m_contactStorage->addSelfEndorseCertificate(*newEndorseCertificate, identity);
-
-  publishSelfEndorseCertificateInDNS(*newEndorseCertificate);
+  decreaseCollectStatus();
 }
 
 void
-ContactManager::updateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity)
+ContactManager::onDnsEndorseeTimeoutNotify(const Interest& interest)
 {
-  shared_ptr<EndorseCertificate> newEndorseCertificate = generateEndorseCertificate(identity, signerIdentity);
-
-  if(!static_cast<bool>(newEndorseCertificate))
-    return;
-
-  m_contactStorage->addEndorseCertificate(*newEndorseCertificate, identity);
-
-  publishEndorseCertificateInDNS(*newEndorseCertificate, signerIdentity);
+  decreaseCollectStatus();
 }
 
-shared_ptr<EndorseCertificate> 
-ContactManager::generateEndorseCertificate(const Name& identity, const Name& signerIdentity)
+void 
+ContactManager::decreaseCollectStatus()
 {
-  shared_ptr<ContactItem> contact = getContact(identity);
-  if(!static_cast<bool>(contact))
-    return shared_ptr<EndorseCertificate>();
+  int count; 
+  {
+    boost::recursive_mutex::scoped_lock lock(m_collectCountMutex);
+    m_collectCount--;
+    count = m_collectCount;
+  }
 
-  Name signerKeyName = m_keyChain->getDefaultKeyNameForIdentity(signerIdentity);
+  if(count == 0)
+    publishCollectEndorsedDataInDNS();
+}
 
-  vector<string> endorseList;
-  m_contactStorage->getEndorseList(identity, endorseList);
+void
+ContactManager::publishCollectEndorsedDataInDNS()
+{
+  Name dnsName = m_identity;
+  dnsName.append("DNS").append("ENDORSED").appendVersion();
 
-  try{
-    shared_ptr<EndorseCertificate> cert = make_shared<EndorseCertificate>(contact->getSelfEndorseCertificate(), signerKeyName, endorseList); 
-    m_keyChain->signByIdentity(*cert, signerIdentity);
-    return cert;
-  }catch(...){
-    return shared_ptr<EndorseCertificate>();
-  } 
+  Data data;
+  data.setName(dnsName);
+
+  EndorseCollection endorseCollection;
+  m_contactStorage->getCollectEndorse(endorseCollection);
+
+  OBufferStream os;
+  endorseCollection.SerializeToOstream(&os);
+
+  data.setContent(os.buf());  
+  m_keyChain.signByIdentity(data, m_identity);
+
+  m_contactStorage->updateDnsOthersEndorse(data);
+  m_face->put(data);
+}
+
+void
+ContactManager::onIdentityCertValidated(const shared_ptr<const Data>& data)
+{
+  shared_ptr<IdentityCertificate> cert = make_shared<IdentityCertificate>(boost::cref(*data));
+  m_bufferedIdCerts[cert->getName()] = cert;
+  decreaseIdCertCount();
+}
+
+void
+ContactManager::onIdentityCertValidationFailed(const shared_ptr<const Data>& data)
+{
+  _LOG_DEBUG("ContactManager::onIdentityCertValidationFailed " << data->getName());
+  decreaseIdCertCount();
+}
+
+void
+ContactManager::onIdentityCertTimeoutNotify(const Interest& interest)
+{
+  _LOG_DEBUG("ContactManager::onIdentityCertTimeoutNotify: " << interest.getName());
+  decreaseIdCertCount();
+}
+
+void
+ContactManager::decreaseIdCertCount()
+{
+  int count;
+  {
+    boost::recursive_mutex::scoped_lock lock(m_idCertCountMutex);
+    m_idCertCount--;
+    count = m_idCertCount;
+  }
+
+  if(count == 0)
+    {
+      QStringList certNameList;
+      QStringList nameList;
+
+      BufferedIdCerts::const_iterator it  = m_bufferedIdCerts.begin();
+      BufferedIdCerts::const_iterator end = m_bufferedIdCerts.end();
+      for(; it != end; it++)
+        {
+          certNameList << QString::fromStdString(it->second->getName().toUri());
+          Profile profile(*(it->second));
+          nameList << QString::fromStdString(profile.get("name"));
+        }
+
+      emit idCertNameListReady(certNameList);
+      emit nameListReady(nameList);
+    }
 }
 
 shared_ptr<EndorseCertificate>
-ContactManager::getSignedSelfEndorseCertificate(const Name& identity,
-                                                const Profile& profile)
+ContactManager::getSignedSelfEndorseCertificate(const Profile& profile)
 {
-  Name certificateName = m_keyChain->getDefaultCertificateNameForIdentity(identity);
-  if(0 == certificateName.size())
-    return shared_ptr<EndorseCertificate>();
+  Name certificateName = m_keyChain.getDefaultCertificateNameForIdentity(m_identity);
 
-  Name signingKeyName = IdentityCertificate::certificateNameToPublicKeyName(certificateName);
-  shared_ptr<IdentityCertificate> kskCert;
-
-  if(signingKeyName.get(-1).toEscapedString().substr(0,4) == "dsk-")
-    {
-      shared_ptr<IdentityCertificate> signingCert = m_keyChain->getCertificate(certificateName);
-      if(!static_cast<bool>(signingCert))
-        return shared_ptr<EndorseCertificate>();
-
-      try{
-        SignatureSha256WithRsa dskCertSig(signingCert->getSignature());
-        Name keyName = IdentityCertificate::certificateNameToPublicKeyName(dskCertSig.getKeyLocator().getName());
-        Name kskCertName = m_keyChain->getDefaultCertificateNameForKey(keyName);
-        kskCert = m_keyChain->getCertificate(kskCertName);
-      }catch(...){
-        return shared_ptr<EndorseCertificate>();
-      }
-    }      
-  else
-    kskCert = m_keyChain->getCertificate(certificateName);
-
-  if(!static_cast<bool>(kskCert))
-    return shared_ptr<EndorseCertificate>();
+  shared_ptr<IdentityCertificate> signingCert = m_keyChain.getCertificate(certificateName);
 
   vector<string> endorseList;
   Profile::const_iterator it = profile.begin();
   for(; it != profile.end(); it++)
     endorseList.push_back(it->first);
   
-  try{
-    shared_ptr<EndorseCertificate> selfEndorseCertificate = make_shared<EndorseCertificate>(*kskCert, profile, endorseList);
-    m_keyChain->sign(*selfEndorseCertificate, kskCert->getName());
-    return selfEndorseCertificate;
-  }catch(...){
-    return shared_ptr<EndorseCertificate>();
-  } 
+  shared_ptr<EndorseCertificate> selfEndorseCertificate = 
+    shared_ptr<EndorseCertificate>(new EndorseCertificate(*signingCert, profile, endorseList));
+  
+  m_keyChain.sign(*selfEndorseCertificate, certificateName);
+  
+  return selfEndorseCertificate;
 }
 
 void
 ContactManager::publishSelfEndorseCertificateInDNS(const EndorseCertificate& selfEndorseCertificate)
 {
-  Data data;
-
-  Name identity = selfEndorseCertificate.getPublicKeyName().getPrefix(-1);
-
-  Name dnsName = identity;
+  Name dnsName = m_identity;
   dnsName.append("DNS").append("PROFILE").appendVersion();
+
+  Data data;
   data.setName(dnsName);
   data.setContent(selfEndorseCertificate.wireEncode());
+  data.setFreshnessPeriod(1000);
 
-  m_keyChain->signByIdentity(data, identity);
-  m_dnsStorage->updateDnsSelfProfileData(data, identity);
+  m_keyChain.signByIdentity(data, m_identity);
+
+  m_contactStorage->updateDnsSelfProfileData(data);
   m_face->put(data);
 }
 
-void
-ContactManager::publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate, const Name& signerIdentity)
+shared_ptr<EndorseCertificate> 
+ContactManager::generateEndorseCertificate(const Name& identity)
 {
-  Data data;
+  shared_ptr<Contact> contact = getContact(identity);
+  if(!static_cast<bool>(contact))
+    return shared_ptr<EndorseCertificate>();
 
+  Name signerKeyName = m_keyChain.getDefaultKeyNameForIdentity(m_identity);
+
+  vector<string> endorseList;
+  m_contactStorage->getEndorseList(identity, endorseList);
+
+  shared_ptr<EndorseCertificate> cert = 
+    shared_ptr<EndorseCertificate>(new EndorseCertificate(contact->getPublicKeyName(), 
+                                                          contact->getPublicKey(),
+                                                          contact->getNotBefore(),
+                                                          contact->getNotAfter(),
+                                                          signerKeyName, 
+                                                          contact->getProfile(), 
+                                                          endorseList)); 
+  m_keyChain.signByIdentity(*cert, m_identity);
+  return cert;
+
+}
+
+void
+ContactManager::publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate)
+{
   Name endorsee = endorseCertificate.getPublicKeyName().getPrefix(-1);
+  Name dnsName = m_identity;
+  dnsName.append("DNS")
+    .append(endorsee.wireEncode())
+    .append("ENDORSEE")
+    .appendVersion();
 
-  Name dnsName = signerIdentity;
-  dnsName.append("DNS").append(endorsee.wireEncode()).append("ENDORSEE").appendVersion();
+  Data data;
   data.setName(dnsName);
-
   data.setContent(endorseCertificate.wireEncode());
 
-  m_keyChain->signByIdentity(data, signerIdentity);
-  m_dnsStorage->updateDnsEndorseOthers(data, signerIdentity, endorsee);
+  m_keyChain.signByIdentity(data, m_identity);
+
+  m_contactStorage->updateDnsEndorseOthers(data, dnsName.get(-3).toEscapedString());
   m_face->put(data);
 }
 
 void
-ContactManager::publishCollectEndorsedDataInDNS(const Name& identity)
+ContactManager::sendInterest(const Interest& interest,
+                             const OnDataValidated& onValidated,
+                             const OnDataValidationFailed& onValidationFailed,
+                             const TimeoutNotify& timeoutNotify,
+                             int retry /* = 1 */)
 {
-  Data data;
+  m_face->expressInterest(interest, 
+                          bind(&ContactManager::onTargetData, 
+                               this, _1, _2, onValidated, onValidationFailed),
+                          bind(&ContactManager::onTargetTimeout,
+                               this, _1, retry, onValidated, onValidationFailed, timeoutNotify));
+}
 
-  Name dnsName = identity;
-  dnsName.append("DNS").append("ENDORSED").appendVersion();
-  data.setName(dnsName);
-  
-  vector<Buffer> collectEndorseList;
-  m_contactStorage->getCollectEndorseList(identity, collectEndorseList);
-  
-  Chronos::EndorseCollection endorseCollection;
+void
+ContactManager::onTargetData(const Interest& interest, 
+                             const Data& data,
+                             const OnDataValidated& onValidated,
+                             const OnDataValidationFailed& onValidationFailed)
+{
+  // _LOG_DEBUG("On receiving data: " << data.getName());
+  m_validator->validate(data, onValidated, onValidationFailed); 
+}
 
-  vector<Buffer>::const_iterator it = collectEndorseList.begin();
-  for(; it != collectEndorseList.end(); it++)
+void
+ContactManager::onTargetTimeout(const Interest& interest, 
+                                int retry,
+                                const OnDataValidated& onValidated,
+                                const OnDataValidationFailed& onValidationFailed,
+                                const TimeoutNotify& timeoutNotify)
+{
+  // _LOG_DEBUG("On interest timeout: " << interest.getName());
+  if(retry > 0)
+    sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, retry-1);
+  else
+    timeoutNotify(interest);
+}
+
+void
+ContactManager::onDnsInterest(const Name& prefix, const Interest& interest)
+{
+  const Name& interestName = interest.getName();
+  shared_ptr<Data> data;
+  
+  if(interestName.size() <= prefix.size())
+    return;
+
+  if(interestName.size() == (prefix.size()+1))
     {
-      string entryStr(reinterpret_cast<const char*>(it->buf()), it->size());
-      endorseCollection.add_endorsement()->set_blob(entryStr);
+      data = m_contactStorage->getDnsData("N/A", interestName.get(prefix.size()).toEscapedString());
+      if(static_cast<bool>(data))
+        m_face->put(*data);
+      return;
     }
 
-  string encoded;
-  endorseCollection.SerializeToString(&encoded);
-
-  data.setContent(reinterpret_cast<const uint8_t*>(encoded.c_str()), encoded.size());
+  if(interestName.size() == (prefix.size()+2))
+    {
+      data = m_contactStorage->getDnsData(interestName.get(prefix.size()).toEscapedString(),
+                                          interestName.get(prefix.size()+1).toEscapedString());
+      if(static_cast<bool>(data))
+        m_face->put(*data);
+      return;
+    }
+}
   
-  m_keyChain->signByIdentity(data, identity);
-  m_dnsStorage->updateDnsOthersEndorse(data, identity);
-  m_face->put(data);
+void
+ContactManager::onDnsRegisterFailed(const Name& prefix, const string& failInfo)
+{
+  emit warning(QString(failInfo.c_str()));
+}
+
+
+// public slots
+void
+ContactManager::onIdentityUpdated(const QString& identity)
+{
+  m_identity = Name(identity.toStdString());
+
+  m_contactStorage = make_shared<ContactStorage>(m_identity);
+
+  if(m_dnsListenerId)
+    m_face->unsetInterestFilter(m_dnsListenerId);
+
+  Name dnsPrefix;
+  dnsPrefix.append(m_identity).append("DNS");
+  m_dnsListenerId = m_face->setInterestFilter(dnsPrefix, 
+                                              bind(&ContactManager::onDnsInterest, this, _1, _2),
+                                              bind(&ContactManager::onDnsRegisterFailed, this, _1, _2));
+
+  m_contactList.clear();
+  m_contactStorage->getAllContacts(m_contactList);
+
+  m_bufferedContacts.clear();
+
+  collectEndorsement();
 }
 
 void
-ContactManager::addContact(const IdentityCertificate& identityCertificate, const Profile& profile)
+ContactManager::onFetchContactInfo(const QString& identity)
 {
-  try{
-    EndorseCertificate endorseCertificate(identityCertificate, profile);
-    
-    m_keyChain->signByIdentity(endorseCertificate, m_defaultIdentity);
+  // try to fetch self-endorse-certificate via DNS PROFILE first.
+  Name identityName(identity.toStdString());
+  Name interestName;
+  interestName.append(identityName).append("DNS").append("PROFILE");
 
-    ContactItem contactItem(endorseCertificate);
+  // _LOG_DEBUG("onFetchContactInfo " << identity.toStdString() << " profile: " << interestName);
+  
+  Interest interest(interestName);
+  interest.setInterestLifetime(1000);
+  interest.setMustBeFresh(true);
 
-    m_contactStorage->addContact(contactItem);
+  OnDataValidated onValidated = bind(&ContactManager::onDnsSelfEndorseCertValidated, this, _1, identityName);
+  OnDataValidationFailed onValidationFailed = bind(&ContactManager::onDnsSelfEndorseCertValidationFailed, this, _1, identityName);
+  TimeoutNotify timeoutNotify = bind(&ContactManager::onDnsSelfEndorseCertTimeoutNotify, this, _1, identityName);
 
-    emit contactAdded(contactItem.getNameSpace());
+  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
+}
 
-  }catch(std::runtime_error& e){
-    emit warning(e.what());
-    _LOG_ERROR("Exception: " << e.what());
+void
+ContactManager::onAddFetchedContact(const QString& identity)
+{
+  // _LOG_DEBUG("onAddFetchedContact");
+
+  Name identityName(identity.toStdString());
+
+  BufferedContacts::const_iterator it = m_bufferedContacts.find(identityName);
+  if(it != m_bufferedContacts.end())
+    {
+      Contact contact(*(it->second.m_selfEndorseCert));
+      // _LOG_DEBUG("onAddFetchedContact: contact ready");
+      try
+        {
+          m_contactStorage->addContact(contact);
+          m_bufferedContacts.erase(identityName);
+
+          m_contactList.clear();
+          m_contactStorage->getAllContacts(m_contactList);
+
+          onWaitForContactList();
+        }
+      catch(ContactStorage::Error& e)
+        {
+          emit warning(QString::fromStdString(e.what()));
+        }
+    }
+  else
+    {
+      emit warning(QString("Failure: no information of %1").arg(identity));
+    }
+}
+
+void
+ContactManager::onUpdateProfile()
+{
+  // Get current profile;
+  shared_ptr<Profile> newProfile = m_contactStorage->getSelfProfile();
+  if(!static_cast<bool>(newProfile))
     return;
+
+  _LOG_DEBUG("ContactManager::onUpdateProfile: getProfile");
+
+  shared_ptr<EndorseCertificate> newEndorseCertificate = getSignedSelfEndorseCertificate(*newProfile);
+
+  m_contactStorage->addSelfEndorseCertificate(*newEndorseCertificate);
+
+  publishSelfEndorseCertificateInDNS(*newEndorseCertificate);
+}
+
+void
+ContactManager::onRefreshBrowseContact()
+{
+  return; // the website info is not available.
+
+  std::vector<std::string> bufferedIdCertNames;
+  try
+    {
+      using namespace boost::asio::ip;
+      tcp::iostream request_stream;
+      request_stream.expires_from_now(boost::posix_time::milliseconds(5000));
+      request_stream.connect("ndncert.named-data.net","80");
+      if(!request_stream)
+        {
+          emit warning(QString::fromStdString("Fail to fetch certificate directory! #1"));
+          return;
+        }
+
+      request_stream << "GET /cert/list/ HTTP/1.0\r\n";
+      request_stream << "Host: ndncert.named-data.net\r\n\r\n";
+      request_stream.flush();
+
+      string line1;
+      std::getline(request_stream,line1);
+      if (!request_stream)
+        {
+          emit warning(QString::fromStdString("Fail to fetch certificate directory! #2"));
+          return;
+        }
+
+      std::stringstream response_stream(line1);
+      std::string http_version;
+      response_stream >> http_version;
+      unsigned int status_code;
+      response_stream >> status_code;
+      std::string status_message;
+      std::getline(response_stream,status_message);
+
+      if (!response_stream||http_version.substr(0,5)!="HTTP/")
+        {
+          emit warning(QString::fromStdString("Fail to fetch certificate directory! #3"));
+          return;
+        }
+      if (status_code!=200)
+        {
+          emit warning(QString::fromStdString("Fail to fetch certificate directory! #4"));
+          return;
+        }
+      vector<string> headers;
+      std::string header;
+      while (std::getline(request_stream, header) && header != "\r")
+        headers.push_back(header);
+
+      std::istreambuf_iterator<char> stream_iter (request_stream);
+      std::istreambuf_iterator<char> end_of_stream;
+      
+      typedef boost::tokenizer< boost::escaped_list_separator<char>, std::istreambuf_iterator<char> > tokenizer_t;
+      tokenizer_t certItems (stream_iter, end_of_stream,boost::escaped_list_separator<char>('\\', '\n', '"'));
+
+      for (tokenizer_t::iterator it = certItems.begin(); it != certItems.end (); it++)
+        if (!it->empty())
+          bufferedIdCertNames.push_back(*it);
+    }
+  catch(std::exception &e)
+    {
+      emit warning(QString::fromStdString("Fail to fetch certificate directory! #N"));
+    }
+
+  {
+    boost::recursive_mutex::scoped_lock lock(m_idCertCountMutex);
+    m_idCertCount = bufferedIdCertNames.size();
   }
+  m_bufferedIdCerts.clear();
+
+  std::vector<std::string>::const_iterator it  = bufferedIdCertNames.begin();
+  std::vector<std::string>::const_iterator end = bufferedIdCertNames.end();
+  for(; it != end; it++)
+    {
+      Name certName(*it);
+
+      Interest interest(certName);
+      interest.setInterestLifetime(1000);
+      interest.setMustBeFresh(true);
+      
+      OnDataValidated onValidated = bind(&ContactManager::onIdentityCertValidated, this, _1);
+      OnDataValidationFailed onValidationFailed = bind(&ContactManager::onIdentityCertValidationFailed, this, _1);
+      TimeoutNotify timeoutNotify = bind(&ContactManager::onIdentityCertTimeoutNotify, this, _1);
+
+      sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
+    }
+  
 }
 
 void
-ContactManager::removeContact(const Name& contactNameSpace)
+ContactManager::onFetchIdCert(const QString& qCertName)
 {
-  shared_ptr<ContactItem> contact = getContact(contactNameSpace);
-  if(!static_cast<bool>(contact))
-    return;
-  m_contactStorage->removeContact(contactNameSpace);
-  emit contactRemoved(contact->getPublicKeyName());
+  Name certName(qCertName.toStdString());
+  if(m_bufferedIdCerts.find(certName) != m_bufferedIdCerts.end())
+    {
+      emit idCertReady(*m_bufferedIdCerts[certName]);
+    }
 }
 
-}//chronos
+void
+ContactManager::onAddFetchedContactIdCert(const QString& qCertName)
+{
+  Name certName(qCertName.toStdString());
+  Name identity = IdentityCertificate::certificateNameToPublicKeyName(certName).getPrefix(-1);
+
+  BufferedIdCerts::const_iterator it = m_bufferedIdCerts.find(certName);
+  if(it != m_bufferedIdCerts.end())
+    {
+      Contact contact(*it->second);
+      try
+        {
+          m_contactStorage->addContact(contact);
+          m_bufferedIdCerts.erase(certName);
+
+          m_contactList.clear();
+          m_contactStorage->getAllContacts(m_contactList);
+
+          onWaitForContactList();
+        }
+      catch(ContactStorage::Error& e)
+        {
+          emit warning(QString::fromStdString(e.what()));
+        }
+    }
+  else
+    emit warning(QString("Failure: no information of %1").arg(QString::fromStdString(identity.toUri())));
+}
+
+void
+ContactManager::onWaitForContactList()
+{
+  ContactList::const_iterator it  = m_contactList.begin();
+  ContactList::const_iterator end = m_contactList.end();
+  
+  QStringList aliasList;
+  QStringList idList;
+  for(; it != end; it++)
+    {
+      aliasList << QString((*it)->getAlias().c_str());
+      idList << QString((*it)->getNameSpace().toUri().c_str());
+    }
+  
+  emit contactAliasListReady(aliasList);
+  emit contactIdListReady(idList);
+}
+
+void
+ContactManager::onWaitForContactInfo(const QString& identity)
+{
+  ContactList::const_iterator it  = m_contactList.begin();
+  ContactList::const_iterator end = m_contactList.end();
+
+  for(; it != end; it++)
+    if((*it)->getNameSpace().toUri() == identity.toStdString())
+      emit contactInfoReady(QString((*it)->getNameSpace().toUri().c_str()),
+                            QString((*it)->getName().c_str()),
+                            QString((*it)->getInstitution().c_str()),
+                            (*it)->isIntroducer());
+}
+
+void
+ContactManager::onRemoveContact(const QString& identity)
+{
+  m_contactStorage->removeContact(Name(identity.toStdString()));
+  m_contactList.clear();
+  m_contactStorage->getAllContacts(m_contactList);
+
+  onWaitForContactList();
+}
+
+void
+ContactManager::onUpdateAlias(const QString& identity, const QString& alias)
+{
+  m_contactStorage->updateAlias(Name(identity.toStdString()), alias.toStdString());
+  m_contactList.clear();
+  m_contactStorage->getAllContacts(m_contactList);
+
+  onWaitForContactList();
+}
+
+void
+ContactManager::onUpdateIsIntroducer(const QString& identity, bool isIntroducer)
+{
+  m_contactStorage->updateIsIntroducer(Name(identity.toStdString()), isIntroducer);
+}
+
+void
+ContactManager::onUpdateEndorseCertificate(const QString& identity)
+{
+  Name identityName(identity.toStdString());
+  shared_ptr<EndorseCertificate> newEndorseCertificate = generateEndorseCertificate(identityName);
+
+  if(!static_cast<bool>(newEndorseCertificate))
+    return;
+
+  m_contactStorage->addEndorseCertificate(*newEndorseCertificate, identityName);
+
+  publishEndorseCertificateInDNS(*newEndorseCertificate);
+}
+
+} // namespace chronos
 
 
 #if WAF