major change: Add security support & Adjust GUI

Change-Id: I7abef37169dec1ef4b68e760dee5214c147c1915
diff --git a/src/add-contact-panel.cpp b/src/add-contact-panel.cpp
new file mode 100644
index 0000000..5ce575c
--- /dev/null
+++ b/src/add-contact-panel.cpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "add-contact-panel.h"
+#include "ui_add-contact-panel.h"
+
+#ifndef Q_MOC_RUN
+#endif
+
+AddContactPanel::AddContactPanel(QWidget *parent)
+  : QDialog(parent)
+  , ui(new Ui::AddContactPanel)
+{
+  ui->setupUi(this);
+
+  connect(ui->cancelButton, SIGNAL(clicked()),
+          this, SLOT(onCancelClicked()));
+  connect(ui->searchButton, SIGNAL(clicked()),
+          this, SLOT(onSearchClicked()));
+  connect(ui->addButton, SIGNAL(clicked()),
+          this, SLOT(onAddClicked()));
+
+  ui->infoView->setColumnCount(3);
+
+  m_typeHeader = new QTableWidgetItem(QString("Type"));
+  ui->infoView->setHorizontalHeaderItem(0, m_typeHeader);
+  m_valueHeader = new QTableWidgetItem(QString("Value"));
+  ui->infoView->setHorizontalHeaderItem(1, m_valueHeader);
+  m_endorseHeader = new QTableWidgetItem(QString("Endorse"));
+  ui->infoView->setHorizontalHeaderItem(2, m_endorseHeader);
+
+}
+
+AddContactPanel::~AddContactPanel()
+{
+  delete m_typeHeader;
+  delete m_valueHeader;
+  delete m_endorseHeader;
+
+  delete ui;
+}
+
+void
+AddContactPanel::onCancelClicked()
+{
+  this->close(); 
+}
+
+void
+AddContactPanel::onSearchClicked()
+{
+  // ui->infoView->clear();
+  for(int i = ui->infoView->rowCount() - 1; i >= 0 ; i--)
+    ui->infoView->removeRow(i);
+
+  m_searchIdentity = ui->contactInput->text();
+  emit fetchInfo(m_searchIdentity);
+}
+
+void
+AddContactPanel::onAddClicked()
+{
+  emit addContact(m_searchIdentity);
+  this->close();
+}
+
+void
+AddContactPanel::onContactEndorseInfoReady(const chronos::EndorseInfo& endorseInfo)
+{
+  int entrySize = endorseInfo.endorsement_size();
+
+  for(int rowCount = 0; rowCount < entrySize; rowCount++)
+    {
+      ui->infoView->insertRow(rowCount);  
+      QTableWidgetItem* type = new QTableWidgetItem(QString::fromStdString(endorseInfo.endorsement(rowCount).type()));
+      ui->infoView->setItem(rowCount, 0, type);
+    
+      QTableWidgetItem* value = new QTableWidgetItem(QString::fromStdString(endorseInfo.endorsement(rowCount).value()));
+      ui->infoView->setItem(rowCount, 1, value);
+
+      QTableWidgetItem* endorse = new QTableWidgetItem(QString::fromStdString(endorseInfo.endorsement(rowCount).endorse()));
+      ui->infoView->setItem(rowCount, 2, endorse);
+    }
+}
+
+
+#if WAF
+#include "add-contact-panel.moc"
+#include "add-contact-panel.cpp.moc"
+#endif
diff --git a/src/add-contact-panel.h b/src/add-contact-panel.h
new file mode 100644
index 0000000..5e8255d
--- /dev/null
+++ b/src/add-contact-panel.h
@@ -0,0 +1,65 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef ADD_CONTACT_PANEL_H
+#define ADD_CONTACT_PANEL_H
+
+#include <QDialog>
+#include <QTableWidgetItem>
+
+#ifndef Q_MOC_RUN
+#include "endorse-info.pb.h"
+#endif
+
+namespace Ui {
+class AddContactPanel;
+}
+
+class AddContactPanel : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit 
+  AddContactPanel(QWidget *parent = 0);
+
+  ~AddContactPanel();
+
+public slots:
+  void
+  onContactEndorseInfoReady(const chronos::EndorseInfo& endorseInfo);
+
+private slots:
+  void
+  onCancelClicked();
+  
+  void
+  onSearchClicked();
+
+  void
+  onAddClicked();
+
+signals:
+  void
+  fetchInfo(const QString& identity);
+
+  void
+  addContact(const QString& identity);
+
+private:
+  Ui::AddContactPanel *ui;
+  QString m_searchIdentity;
+
+  QTableWidgetItem* m_typeHeader;
+  QTableWidgetItem* m_valueHeader;
+  QTableWidgetItem* m_endorseHeader;
+};
+
+#endif // ADD_CONTACT_PANEL_H
diff --git a/src/add-contact-panel.ui b/src/add-contact-panel.ui
new file mode 100644
index 0000000..5cf399a
--- /dev/null
+++ b/src/add-contact-panel.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AddContactPanel</class>
+ <widget class="QDialog" name="AddContactPanel">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>500</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Add Contact</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QVBoxLayout" name="addContactPanelLayout" stretch="1,30,1">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <item>
+      <layout class="QHBoxLayout" name="contactSearchLayout" stretch="3,5,2">
+       <item>
+        <widget class="QLabel" name="contactLabel">
+         <property name="font">
+          <font>
+           <weight>75</weight>
+           <bold>true</bold>
+          </font>
+         </property>
+         <property name="text">
+          <string>Contact identity:</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::AutoText</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLineEdit" name="contactInput"/>
+       </item>
+       <item>
+        <widget class="QPushButton" name="searchButton">
+         <property name="text">
+          <string>Fetch</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="QTableWidget" name="infoView">
+       <attribute name="horizontalHeaderStretchLastSection">
+        <bool>true</bool>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="buttonLayout">
+       <item>
+        <widget class="QPushButton" name="cancelButton">
+         <property name="text">
+          <string>Cancel</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="addButton">
+         <property name="text">
+          <string>Add</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/addcontactpanel.cpp b/src/addcontactpanel.cpp
deleted file mode 100644
index add341a..0000000
--- a/src/addcontactpanel.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "addcontactpanel.h"
-#include "ui_addcontactpanel.h"
-#include <QMessageBox>
-
-#ifndef Q_MOC_RUN
-#include <ndn-cpp-dev/security/validator.hpp>
-#include <boost/iostreams/stream.hpp>
-#include "endorse-collection.pb.h"
-#include "logging.h"
-#endif
-
-using namespace ndn;
-using namespace chronos;
-using namespace std;
-
-INIT_LOGGER("AddContactPanel");
-
-AddContactPanel::AddContactPanel(shared_ptr<ContactManager> contactManager,
-                                 QWidget *parent) 
-  : QDialog(parent)
-  , ui(new Ui::AddContactPanel)
-  , m_contactManager(contactManager)
-  , m_warningDialog(new WarningDialog())
-{
-  ui->setupUi(this);
-  
-  qRegisterMetaType<ndn::Name>("NdnName");
-  qRegisterMetaType<chronos::EndorseCertificate>("EndorseCertificate");
-  qRegisterMetaType<ndn::Data>("NdnData");
-
-  connect(ui->cancelButton, SIGNAL(clicked()),
-          this, SLOT(onCancelClicked()));
-  connect(ui->searchButton, SIGNAL(clicked()),
-          this, SLOT(onSearchClicked()));
-  connect(ui->addButton, SIGNAL(clicked()),
-          this, SLOT(onAddClicked()));
-  connect(&*m_contactManager, SIGNAL(contactFetched(const chronos::EndorseCertificate&)),
-          this, SLOT(selfEndorseCertificateFetched(const chronos::EndorseCertificate&)));
-  connect(&*m_contactManager, SIGNAL(contactFetchFailed(const ndn::Name&)),
-          this, SLOT(selfEndorseCertificateFetchFailed(const ndn::Name&)));
-  connect(&*m_contactManager, SIGNAL(collectEndorseFetched(const ndn::Data&)),
-          this, SLOT(onCollectEndorseFetched(const ndn::Data&)));
-  connect(&*m_contactManager, SIGNAL(collectEndorseFetchFailed(const ndn::Name&)),
-          this, SLOT(onCollectEndorseFetchFailed(const ndn::Name&)));
-  connect(&*m_contactManager, SIGNAL(contactKeyFetched(const chronos::EndorseCertificate&)),
-          this, SLOT(onContactKeyFetched(const chronos::EndorseCertificate&)));
-  connect(&*m_contactManager, SIGNAL(contactKeyFetchFailed(const ndn::Name&)),
-          this, SLOT(onContactKeyFetchFailed(const ndn::Name&)));
-
-
-}
-
-AddContactPanel::~AddContactPanel()
-{
-    delete ui;
-    delete m_warningDialog;
-}
-
-void
-AddContactPanel::onCancelClicked()
-{ this->close(); }
-
-void
-AddContactPanel::onSearchClicked()
-{
-  m_currentEndorseCertificateReady = false;
-  m_currentCollectEndorseReady = false;
-  ui->infoView->clear();
-  for(int i = ui->infoView->rowCount() - 1; i >= 0 ; i--)
-    ui->infoView->removeRow(i);
-  QString inputIdentity = ui->contactInput->text();
-  m_searchIdentity = Name(inputIdentity.toStdString());
-
-  if(Qt::Checked == ui->fetchBox->checkState())
-    {
-      m_contactManager->fetchSelfEndorseCertificate(m_searchIdentity);
-      m_contactManager->fetchCollectEndorse(m_searchIdentity);
-    }
-  else
-    {
-      if(isCorrectName(m_searchIdentity))
-        m_contactManager->fetchKey(m_searchIdentity);
-      else
-        {
-          QMessageBox::information(this, tr("Chronos"), QString::fromStdString("Wrong key certificate name!"));
-        }
-    }
-}
-
-bool
-AddContactPanel::isCorrectName(const Name& name)
-{
-  if(name.get(-1).toEscapedString() != "ID-CERT")
-    return false;
-  
-  int keyIndex = -1;
-  for(int i = 0; i < name.size(); i++)
-    {
-      if(name.get(i).toEscapedString() == "KEY")
-        {
-          keyIndex = i;
-          break;
-        }
-    }
-  
-  if(keyIndex < 0)
-    return false;
-  else
-    return true;
-}
-
-void
-AddContactPanel::onAddClicked()
-{
-  ContactItem contactItem(*m_currentEndorseCertificate);
-  try{
-    m_contactManager->getContactStorage()->addContact(contactItem);
-  }catch(ContactStorage::Error& e){
-    QMessageBox::information(this, tr("Chronos"), QString::fromStdString(e.what()));
-    _LOG_ERROR("Exception: " << e.what());
-    return;
-  }
-  emit newContactAdded();
-  this->close();
-}
-
-void 
-AddContactPanel::selfEndorseCertificateFetched(const EndorseCertificate& endorseCertificate)
-{
-
-  m_currentEndorseCertificate = make_shared<EndorseCertificate>(endorseCertificate);
-
-  m_currentEndorseCertificateReady = true;
-
-  if(m_currentCollectEndorseReady == true)
-    displayContactInfo();
-}
-
-void
-AddContactPanel::selfEndorseCertificateFetchFailed(const Name& identity)
-{
-  QMessageBox::information(this, tr("Chronos"), QString::fromStdString("Cannot fetch contact profile"));
-}
-
-void
-AddContactPanel::onContactKeyFetched(const EndorseCertificate& endorseCertificate)
-{
-  m_currentEndorseCertificate = make_shared<EndorseCertificate>(endorseCertificate);
-
-  m_currentCollectEndorseReady = false;
-
-  displayContactInfo();
-}
-
-void
-AddContactPanel::onContactKeyFetchFailed(const Name& identity)
-{
-  QMessageBox::information(this, tr("Chronos"), QString::fromStdString("Cannot fetch contact ksk certificate"));
-}
-
-void
-AddContactPanel::onCollectEndorseFetched(const Data& data)
-{
-  m_currentCollectEndorse = make_shared<Data>(data);
-
-  m_currentCollectEndorseReady = true;
-
-  if(m_currentEndorseCertificateReady == true)
-    displayContactInfo();
-}
-
-void
-AddContactPanel::onCollectEndorseFetchFailed(const Name& identity)
-{
-  m_currentCollectEndorse = shared_ptr<Data>();
-
-  m_currentCollectEndorseReady = true;
-  
-  if(m_currentEndorseCertificateReady == true)
-    displayContactInfo();
-}
-
-void
-AddContactPanel::displayContactInfo()
-{
-  // _LOG_TRACE("displayContactInfo");
-  const Profile& profile = m_currentEndorseCertificate->getProfile();
-
-  map<string, int> endorseCount;
-
-  if(!static_cast<bool>(m_currentCollectEndorse))
-    {
-      Chronos::EndorseCollection endorseCollection;
-      
-      boost::iostreams::stream
-        <boost::iostreams::array_source> is (reinterpret_cast<const char*>(m_currentCollectEndorse->getContent().value()), 
-                                             m_currentCollectEndorse->getContent().value_size());
-      
-      endorseCollection.ParseFromIstream(&is);
-
-      for(int i = 0; i < endorseCollection.endorsement_size(); i ++)
-        {
-          try{
-            Data data;
-            data.wireDecode(Block(reinterpret_cast<const uint8_t*>(endorseCollection.endorsement(i).blob().c_str()),
-                                  endorseCollection.endorsement(i).blob().size()));
-            EndorseCertificate endorseCert(data);
-            
-            Name signerName = endorseCert.getSigner().getPrefix(-1);
-          
-            shared_ptr<ContactItem> contact = m_contactManager->getContact(signerName);
-            if(!static_cast<bool>(contact))
-              continue;
-
-            if(!contact->isIntroducer() || !contact->canBeTrustedFor(m_currentEndorseCertificate->getProfile().getIdentityName()))
-              continue;
-          
-            if(!Validator::verifySignature(data, data.getSignature(), contact->getSelfEndorseCertificate().getPublicKeyInfo()))
-              continue;
-
-            const Profile& tmpProfile = endorseCert.getProfile();
-            if(!(profile == tmpProfile))
-              continue;
-
-          const vector<string>& endorseList = endorseCert.getEndorseList();
-          vector<string>::const_iterator it = endorseList.begin();
-          for(; it != endorseList.end(); it++)
-            endorseCount[*it] += 1;
-          }catch(std::runtime_error& e){
-            continue;
-          }
-        }  
-    }
-  
-  ui->infoView->setColumnCount(3);
-  Profile::const_iterator it = profile.begin();
-  int rowCount = 0;
-  
-  QTableWidgetItem *typeHeader = new QTableWidgetItem(QString::fromUtf8("Type"));
-  ui->infoView->setHorizontalHeaderItem(0, typeHeader);
-  QTableWidgetItem *valueHeader = new QTableWidgetItem(QString::fromUtf8("Value"));
-  ui->infoView->setHorizontalHeaderItem(1, valueHeader);
-  QTableWidgetItem *endorseHeader = new QTableWidgetItem(QString::fromUtf8("Endorse"));
-  ui->infoView->setHorizontalHeaderItem(2, endorseHeader);
-  
-  for(; it != profile.end(); it++)
-  {
-    ui->infoView->insertRow(rowCount);  
-    QTableWidgetItem *type = new QTableWidgetItem(QString::fromStdString(it->first));
-    ui->infoView->setItem(rowCount, 0, type);
-    
-    QTableWidgetItem *value = new QTableWidgetItem(QString::fromStdString(it->second));
-    ui->infoView->setItem(rowCount, 1, value);
-    
-    map<string, int>::iterator map_it = endorseCount.find(it->first);
-    QTableWidgetItem *endorse = NULL;
-    if(map_it == endorseCount.end())
-      endorse = new QTableWidgetItem(QString::number(0));
-    else
-      endorse = new QTableWidgetItem(QString::number(map_it->second));
-    ui->infoView->setItem(rowCount, 2, endorse);
-
-    rowCount++;
-  }
-}
-
-
-#if WAF
-#include "addcontactpanel.moc"
-#include "addcontactpanel.cpp.moc"
-#endif
diff --git a/src/addcontactpanel.h b/src/addcontactpanel.h
deleted file mode 100644
index a65635a..0000000
--- a/src/addcontactpanel.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef ADDCONTACTPANEL_H
-#define ADDCONTACTPANEL_H
-
-#include <QDialog>
-#include <QMetaType>
-#include "warningdialog.h"
-
-#ifndef Q_MOC_RUN
-#include "endorse-certificate.h"
-#include "profile.h"
-#include "contact-manager.h"
-#endif
-
-namespace Ui {
-class AddContactPanel;
-}
-
-Q_DECLARE_METATYPE(ndn::Name)
-
-Q_DECLARE_METATYPE(chronos::EndorseCertificate)
-
-Q_DECLARE_METATYPE(ndn::Data)
-
-class AddContactPanel : public QDialog
-{
-  Q_OBJECT
-
-public:
-  explicit AddContactPanel(ndn::shared_ptr<chronos::ContactManager> contactManager,
-                           QWidget *parent = 0);
-
-  ~AddContactPanel();
-
-private:
-  void
-  displayContactInfo();
-
-  bool
-  isCorrectName(const ndn::Name& name);
-
-  // static bool
-  // isSameBlob(const ndn::Blob& blobA, const ndn::Blob& blobB);
-
-private slots:
-  void
-  onCancelClicked();
-  
-  void
-  onSearchClicked();
-
-  void
-  onAddClicked();
-
-  void
-  selfEndorseCertificateFetched(const chronos::EndorseCertificate& endorseCertificate);
-
-  void
-  selfEndorseCertificateFetchFailed(const ndn::Name& identity);
-
-  void
-  onContactKeyFetched(const chronos::EndorseCertificate& endorseCertificate);
-
-  void
-  onContactKeyFetchFailed(const ndn::Name& identity);
-
-  void
-  onCollectEndorseFetched(const ndn::Data& data);
-
-  void
-  onCollectEndorseFetchFailed(const ndn::Name& identity);
-
-signals:
-  void
-  newContactAdded();
-
-private:
-
-  Ui::AddContactPanel *ui;
-  ndn::Name m_searchIdentity;
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-  WarningDialog* m_warningDialog;
-  ndn::shared_ptr<chronos::EndorseCertificate> m_currentEndorseCertificate;
-  ndn::shared_ptr<ndn::Data> m_currentCollectEndorse;
-  bool m_currentEndorseCertificateReady;
-  bool m_currentCollectEndorseReady;
-};
-
-#endif // ADDCONTACTPANEL_H
diff --git a/src/addcontactpanel.ui b/src/addcontactpanel.ui
deleted file mode 100644
index fb6f4fa..0000000
--- a/src/addcontactpanel.ui
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>AddContactPanel</class>
- <widget class="QDialog" name="AddContactPanel">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>500</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Add Contact</string>
-  </property>
-  <widget class="QWidget" name="layoutWidget">
-   <property name="geometry">
-    <rect>
-     <x>10</x>
-     <y>10</y>
-     <width>381</width>
-     <height>481</height>
-    </rect>
-   </property>
-   <layout class="QVBoxLayout" name="addContactPanelLayout" stretch="1,25,0,1">
-    <property name="spacing">
-     <number>10</number>
-    </property>
-    <item>
-     <layout class="QHBoxLayout" name="contactSearchLayout" stretch="1,5,2">
-      <item>
-       <widget class="QLabel" name="contactLabel">
-        <property name="font">
-         <font>
-          <weight>75</weight>
-          <bold>true</bold>
-         </font>
-        </property>
-        <property name="text">
-         <string>Contact:</string>
-        </property>
-        <property name="textFormat">
-         <enum>Qt::AutoText</enum>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QLineEdit" name="contactInput"/>
-      </item>
-      <item>
-       <widget class="QPushButton" name="searchButton">
-        <property name="text">
-         <string>Fetch</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-    <item>
-     <widget class="QTableWidget" name="infoView">
-      <attribute name="horizontalHeaderStretchLastSection">
-       <bool>true</bool>
-      </attribute>
-     </widget>
-    </item>
-    <item>
-     <widget class="QCheckBox" name="fetchBox">
-      <property name="text">
-       <string>Fetch profile</string>
-      </property>
-      <property name="checkable">
-       <bool>true</bool>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <layout class="QHBoxLayout" name="buttonLayout">
-      <item>
-       <widget class="QPushButton" name="cancelButton">
-        <property name="text">
-         <string>Cancel</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="addButton">
-        <property name="text">
-         <string>Add</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/browse-contact-dialog.cpp b/src/browse-contact-dialog.cpp
new file mode 100644
index 0000000..5cf2ba9
--- /dev/null
+++ b/src/browse-contact-dialog.cpp
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+
+#include "browse-contact-dialog.h"
+#include "ui_browse-contact-dialog.h"
+
+#ifndef Q_MOC_RUN
+#include "profile.h"
+#endif
+
+using namespace std;
+using namespace ndn;
+using namespace chronos;
+
+BrowseContactDialog::BrowseContactDialog(QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::BrowseContactDialog)
+  , m_contactListModel(new QStringListModel)
+{
+  ui->setupUi(this);
+
+  m_typeHeader = new QTableWidgetItem(QString("Type"));
+  m_valueHeader = new QTableWidgetItem(QString("Value"));
+  ui->InfoTable->setHorizontalHeaderItem(0, m_typeHeader);
+  ui->InfoTable->setHorizontalHeaderItem(1, m_valueHeader);
+
+  ui->ContactList->setModel(m_contactListModel);
+
+  connect(ui->ContactList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+          this, SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
+  connect(ui->AddButton, SIGNAL(clicked()),
+	  this, SLOT(onAddClicked()));
+  connect(ui->DirectAddButton, SIGNAL(clicked()),
+	  this, SLOT(onDirectAddClicked()));
+}
+
+BrowseContactDialog::~BrowseContactDialog()
+{
+  delete m_typeHeader;
+  delete m_valueHeader;
+  delete ui;
+}
+
+void
+BrowseContactDialog::onSelectionChanged(const QItemSelection& selected,
+                                        const QItemSelection& deselected)
+{
+  QModelIndexList items = selected.indexes();
+  QString certName = m_contactCertNameList[items.first().row()];
+  emit fetchIdCert(certName);
+}
+
+void
+BrowseContactDialog::onAddClicked()
+{
+  QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
+  QModelIndexList selectedList = selectionModel->selectedIndexes();
+  QModelIndexList::iterator it = selectedList.begin();
+  for(; it != selectedList.end(); it++)
+    emit addContact(m_contactNameList[it->row()]);
+
+  this->close();
+}
+
+void
+BrowseContactDialog::onDirectAddClicked()
+{
+  emit directAddClicked();
+  this->close();
+}
+
+void
+BrowseContactDialog::closeEvent(QCloseEvent *e)
+{
+  ui->InfoTable->clear();
+  for(int i = ui->InfoTable->rowCount() - 1; i >= 0 ; i--)
+      ui->InfoTable->removeRow(i);
+  ui->InfoTable->horizontalHeader()->hide();
+
+  hide();
+  e->ignore();
+}
+
+void
+BrowseContactDialog::onIdCertNameListReady(const QStringList& qCertNameList)
+{
+  m_contactCertNameList = qCertNameList;
+}
+
+void
+BrowseContactDialog::onNameListReady(const QStringList& qNameList)
+{
+  m_contactNameList = qNameList;
+  m_contactListModel->setStringList(m_contactNameList);
+}
+
+void
+BrowseContactDialog::onIdCertReady(const IdentityCertificate& idCert)
+{
+  Profile profile(idCert);
+
+  ui->InfoTable->clear();
+
+  for(int i = ui->InfoTable->rowCount() - 1; i >= 0 ; i--)
+    ui->InfoTable->removeRow(i);
+
+  ui->InfoTable->horizontalHeader()->show();
+  ui->InfoTable->setColumnCount(2);
+  
+  Profile::const_iterator proIt = profile.begin();
+  Profile::const_iterator proEnd = profile.end();
+  int rowCount = 0;
+
+  for(; proIt != proEnd; proIt++, rowCount++)
+    {
+      ui->InfoTable->insertRow(rowCount);  
+      QTableWidgetItem* type = new QTableWidgetItem(QString::fromStdString(proIt->first));
+      ui->InfoTable->setItem(rowCount, 0, type);
+      
+      QTableWidgetItem* value = new QTableWidgetItem(QString::fromStdString(proIt->second));
+      ui->InfoTable->setItem(rowCount, 1, value);	  
+    }
+}
+
+#if WAF
+#include "browse-contact-dialog.moc"
+#include "browse-contact-dialog.cpp.moc"
+#endif
diff --git a/src/browse-contact-dialog.h b/src/browse-contact-dialog.h
new file mode 100644
index 0000000..f13770e
--- /dev/null
+++ b/src/browse-contact-dialog.h
@@ -0,0 +1,90 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef BROWSE_CONTACT_DIALOG_H
+#define BROWSE_CONTACT_DIALOG_H
+
+#include <QDialog>
+#include <QStringListModel>
+#include <QCloseEvent>
+#include <QTableWidgetItem>
+
+#ifndef Q_MOC_RUN
+#include <ndn-cpp-dev/security/identity-certificate.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#endif
+
+namespace Ui {
+class BrowseContactDialog;
+}
+
+class BrowseContactDialog : public QDialog
+{
+  Q_OBJECT
+  
+public:
+  explicit 
+  BrowseContactDialog(QWidget *parent = 0);
+
+  ~BrowseContactDialog();
+
+protected:
+  void
+  closeEvent(QCloseEvent *e);
+
+private slots:
+  void
+  onSelectionChanged(const QItemSelection &selected,
+                     const QItemSelection &deselected);
+
+  void
+  onAddClicked();
+
+  void
+  onDirectAddClicked();
+
+public slots:
+  void
+  onIdCertNameListReady(const QStringList& certNameList);
+
+  void
+  onNameListReady(const QStringList& nameList);
+
+  void
+  onIdCertReady(const ndn::IdentityCertificate& idCert);
+
+signals:
+  void
+  directAddClicked();
+  
+  void
+  fetchIdCert(const QString& certName);
+
+  void
+  addContact(const QString& qCertName);
+
+private:
+
+  typedef boost::recursive_mutex RecLock;
+  typedef boost::unique_lock<RecLock> UniqueRecLock;
+
+  Ui::BrowseContactDialog *ui;
+
+  QTableWidgetItem* m_typeHeader;
+  QTableWidgetItem* m_valueHeader;
+
+  QStringListModel* m_contactListModel;
+
+  QStringList m_contactNameList;
+  QStringList m_contactCertNameList;
+};
+
+#endif // BROWSE_CONTACT_DIALOG_H
diff --git a/src/browse-contact-dialog.ui b/src/browse-contact-dialog.ui
new file mode 100644
index 0000000..1ef6355
--- /dev/null
+++ b/src/browse-contact-dialog.ui
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BrowseContactDialog</class>
+ <widget class="QDialog" name="BrowseContactDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>BrowseContacts</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout" stretch="20,1">
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout" stretch="2,3">
+       <item>
+        <widget class="QListView" name="ContactList">
+         <property name="contextMenuPolicy">
+          <enum>Qt::CustomContextMenu</enum>
+         </property>
+         <property name="acceptDrops">
+          <bool>false</bool>
+         </property>
+         <property name="editTriggers">
+          <set>QAbstractItemView::NoEditTriggers</set>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QTableWidget" name="InfoTable">
+         <attribute name="horizontalHeaderStretchLastSection">
+          <bool>true</bool>
+         </attribute>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
+       <item>
+        <widget class="QPushButton" name="AddButton">
+         <property name="text">
+          <string>Add </string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="DirectAddButton">
+         <property name="text">
+          <string>Direct Add</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/browsecontactdialog.cpp b/src/browsecontactdialog.cpp
deleted file mode 100644
index ba0664d..0000000
--- a/src/browsecontactdialog.cpp
+++ /dev/null
@@ -1,338 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-
-#include "browsecontactdialog.h"
-#include "ui_browsecontactdialog.h"
-#include <QMessageBox>
-
-#ifndef Q_MOC_RUN
-#include <boost/asio.hpp>
-#include <boost/tokenizer.hpp>
-#include "logging.h"
-#endif
-
-using namespace std;
-using namespace ndn;
-using namespace chronos;
-
-INIT_LOGGER("BrowseContactDialog");
-
-// Q_DECLARE_METATYPE(ndn::security::IdentityCertificate)
-
-BrowseContactDialog::BrowseContactDialog(shared_ptr<ContactManager> contactManager,
-					 QWidget *parent) 
-  : QDialog(parent)
-  , ui(new Ui::BrowseContactDialog)
-  , m_contactManager(contactManager)
-  , m_warningDialog(new WarningDialog)
-  , m_contactListModel(new QStringListModel)
-{
-  // qRegisterMetaType<ndn::security::IdentityCertificate>("NDNIdentityCertificate");
-
-  ui->setupUi(this);
-
-  ui->ContactList->setModel(m_contactListModel);
-
-  connect(ui->ContactList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
-          this, SLOT(updateSelection(const QItemSelection &, const QItemSelection &)));
-  connect(&*m_contactManager, SIGNAL(contactCertificateFetched(const ndn::IdentityCertificate &)),
-	  this, SLOT(onCertificateFetched(const ndn::IdentityCertificate &)));
-  connect(&*m_contactManager, SIGNAL(contactCertificateFetchFailed(const ndn::Name&)),
-          this, SLOT(onCertificateFetchFailed(const ndn::Name&)));
-  connect(&*m_contactManager, SIGNAL(warning(QString)),
-	  this, SLOT(onWarning(QString)));
-
-  connect(ui->AddButton, SIGNAL(clicked()),
-	  this, SLOT(onAddClicked()));
-	  
-  connect(ui->DirectAddButton, SIGNAL(clicked()),
-	  this, SLOT(onDirectAddClicked()));
-}
-
-BrowseContactDialog::~BrowseContactDialog()
-{
-  delete ui;
-}
-
-
-void
-BrowseContactDialog::getCertNames(vector<string> &names)
-{
-  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)
-      {
-	QMessageBox::information(this, tr("Chronos"), 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)
-      {
-	QMessageBox::information(this, tr("Chronos"), 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/")
-      {
-    	QMessageBox::information(this, tr("Chronos"), QString::fromStdString("Fail to fetch certificate directory! #3"));
-	return;
-      }
-    if (status_code!=200)
-      {
-    	QMessageBox::information(this, tr("Chronos"), 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())
-          {
-            names.push_back(*it);
-          }
-      }
-  }catch(std::exception &e){
-    QMessageBox::information(this, tr("Chronos"), QString::fromStdString("Fail to fetch certificate directory! #N"));
-  }
-}
-
-void
-BrowseContactDialog::updateCertificateMap(bool filter)
-{
-  vector<string> certNameList;
-  getCertNames(certNameList);
-  _LOG_DEBUG("Get Certificate Name List");
-  for(int i = 0; i < certNameList.size(); i++)
-    {
-      _LOG_DEBUG(" " << certNameList[i]);
-    }
-  
-  if(filter)
-    {
-      map<Name, Name> certificateMap;
-
-      vector<string>::iterator it = certNameList.begin();
-  
-      for(; it != certNameList.end(); it++)
-	{
-	  Name newCertName(*it);
-	  Name keyName = IdentityCertificate::certificateNameToPublicKeyName(newCertName);
-	  Name identity = keyName.getPrefix(-1);
-	  
-	  map<Name, Name>::iterator map_it = certificateMap.find(identity);
-	  if(map_it != certificateMap.end())
-	    {
-	      Name oldCertName = map_it->second;
-	      Name oldKeyName = IdentityCertificate::certificateNameToPublicKeyName(oldCertName);
-	      if(keyName.get(-1).toEscapedString() > oldKeyName.get(-1).toEscapedString())
-		map_it->second = newCertName;
-	      else if(keyName == oldKeyName && newCertName.get(-1).toVersion() > oldCertName.get(-1).toVersion())
-		map_it->second = newCertName;
-	    }
-	  else
-	    {
-	      certificateMap.insert(pair<Name, Name>(identity, newCertName));
-	    }
-	}
-      map<Name, Name>::iterator map_it = certificateMap.begin();
-      for(; map_it != certificateMap.end(); map_it++)
-	m_certificateNameList.push_back(map_it->second);
-    }
-  else
-    {
-      vector<string>::iterator it = certNameList.begin();
-  
-      for(; it != certNameList.end(); it++)
-	{
-          m_certificateNameList.push_back(Name (*it));
-          // try {
-          //   m_certificateNameList.push_back(Name (*it));
-          // }
-          // catch(error::Name)
-          //   {
-          //     _LOG_ERROR ("Error parsing: [" << *it << "]");
-          //   }
-          // catch(error::name::Component)
-          //   {
-          //     _LOG_ERROR ("Error parsing: [" << *it << "]");
-          //   }
-	}
-    }
-}
-
-void
-BrowseContactDialog::fetchCertificate()
-{
-  vector<Name>::iterator it = m_certificateNameList.begin();
-  int count = 0;
-  for(; it != m_certificateNameList.end(); it++)
-    {
-      _LOG_DEBUG("fetch " << it->toUri());
-      usleep(1000);
-      m_contactManager->fetchIdCertificate(*it);
-    }
-}
-
-void
-BrowseContactDialog::onCertificateFetched(const IdentityCertificate& identityCertificate)
-{
-  Name certNameNoVersion = identityCertificate.getName().getPrefix(-1);
-  _LOG_DEBUG("Fetch: " << certNameNoVersion.toUri());
-  m_certificateMap.insert(pair<Name, IdentityCertificate>(certNameNoVersion, identityCertificate));
-  m_profileMap.insert(pair<Name, Profile>(certNameNoVersion, Profile(identityCertificate)));
-  string name = m_profileMap[certNameNoVersion].get("name");
-  // Name contactName = m_profileMap[certNameNoVersion].getIdentityName();
-  {
-      UniqueRecLock lock(m_mutex);
-      m_contactList << QString::fromStdString(name);
-      m_contactListModel->setStringList(m_contactList);
-      m_contactNameList.push_back(certNameNoVersion);
-  }    
-}
-
-void
-BrowseContactDialog::onCertificateFetchFailed(const Name& identity)
-{
-  _LOG_DEBUG("Cannot fetch " << identity.toUri());
-}
-
-void
-BrowseContactDialog::refreshList()
-{
-  {
-      UniqueRecLock lock(m_mutex);
-      m_contactList.clear();
-      m_contactNameList.clear();
-  }
-  m_certificateNameList.clear();
-  m_certificateMap.clear();
-  m_profileMap.clear();
-
-  updateCertificateMap();
-
-  fetchCertificate();
-}
-
-void
-BrowseContactDialog::updateSelection(const QItemSelection& selected,
-				     const QItemSelection& deselected)
-{
-  QModelIndexList items = selected.indexes();
-  Name certName = m_contactNameList[items.first().row()];
-
-  ui->InfoTable->clear();
-  for(int i = ui->InfoTable->rowCount() - 1; i >= 0 ; i--)
-    ui->InfoTable->removeRow(i);
-
-  ui->InfoTable->horizontalHeader()->show();
-
-  map<Name, Profile>::iterator it = m_profileMap.find(certName);
-  if(it != m_profileMap.end())
-    {
-      ui->InfoTable->setColumnCount(2);
-
-      QTableWidgetItem *typeHeader = new QTableWidgetItem(QString::fromUtf8("Type"));
-      ui->InfoTable->setHorizontalHeaderItem(0, typeHeader);
-      QTableWidgetItem *valueHeader = new QTableWidgetItem(QString::fromUtf8("Value"));
-      ui->InfoTable->setHorizontalHeaderItem(1, valueHeader);
-
-      Profile::const_iterator pro_it = it->second.begin();
-      int rowCount = 0;        
-  
-      for(; pro_it != it->second.end(); pro_it++, rowCount++)
-	{
-	  ui->InfoTable->insertRow(rowCount);  
-	  QTableWidgetItem *type = new QTableWidgetItem(QString::fromStdString(pro_it->first));
-	  ui->InfoTable->setItem(rowCount, 0, type);
-	  
-	  QTableWidgetItem *value = new QTableWidgetItem(QString::fromStdString(pro_it->second));
-	  ui->InfoTable->setItem(rowCount, 1, value);	  
-	}
-    }
-}
-
-void
-BrowseContactDialog::onWarning(QString msg)
-{
-  m_warningDialog->setMsg(msg.toStdString());
-  m_warningDialog->show();
-}
-
-void
-BrowseContactDialog::onAddClicked()
-{
-  QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
-  QModelIndexList selectedList = selectionModel->selectedIndexes();
-  QModelIndexList::iterator it = selectedList.begin();
-  for(; it != selectedList.end(); it++)
-    {
-      Name certName = m_contactNameList[it->row()];
-      if(m_certificateMap.find(certName) != m_certificateMap.end() && m_profileMap.find(certName) != m_profileMap.end())
-	m_contactManager->addContact(m_certificateMap[certName], m_profileMap[certName]);
-      else
-	{
-	  m_warningDialog->setMsg("Not enough information to add contact!");
-	  m_warningDialog->show();
-	}
-    }
-  emit newContactAdded();
-  this->close();
-}
-
-void
-BrowseContactDialog::onDirectAddClicked()
-{
-  emit directAddClicked();
-  this->close();
-}
-
-void
-BrowseContactDialog::closeEvent(QCloseEvent *e)
-{
-  ui->InfoTable->clear();
-  for(int i = ui->InfoTable->rowCount() - 1; i >= 0 ; i--)
-      ui->InfoTable->removeRow(i);
-  ui->InfoTable->horizontalHeader()->hide();
-
-  hide();
-  e->ignore();
-}
-
-#if WAF
-#include "browsecontactdialog.moc"
-#include "browsecontactdialog.cpp.moc"
-#endif
diff --git a/src/browsecontactdialog.h b/src/browsecontactdialog.h
deleted file mode 100644
index 5cd610f..0000000
--- a/src/browsecontactdialog.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-
-#ifndef BROWSECONTACTDIALOG_H
-#define BROWSECONTACTDIALOG_H
-
-#include <QDialog>
-#include <QStringListModel>
-#include <QCloseEvent>
-#include "warningdialog.h"
-
-
-#ifndef Q_MOC_RUN
-#include <ndn-cpp-dev/security/identity-certificate.hpp>
-#include <boost/thread/locks.hpp>
-#include <boost/thread/recursive_mutex.hpp>
-#include "profile.h"
-#include "contact-manager.h"
-#endif
-
-namespace Ui {
-class BrowseContactDialog;
-}
-
-class BrowseContactDialog : public QDialog
-{
-  Q_OBJECT
-  
-public:
-  explicit BrowseContactDialog(ndn::shared_ptr<chronos::ContactManager> contactManager,
-                               QWidget *parent = 0);
-
-  ~BrowseContactDialog();
-
-protected:
-  typedef boost::recursive_mutex RecLock;
-  typedef boost::unique_lock<RecLock> UniqueRecLock;
-
-private:
-  void
-  getCertNames(std::vector<std::string>& names);
-
-  void
-  updateCertificateMap(bool filter = false);
-
-  void
-  updateCertificateFetchingStatus(int count);
-
-  void
-  fetchCertificate();
-
-protected:
-  void
-  closeEvent(QCloseEvent *e);
-
-private slots:
-  void
-  updateSelection(const QItemSelection &selected,
-                  const QItemSelection &deselected);
-
-  void
-  onCertificateFetched(const ndn::IdentityCertificate& identityCertificate);
-
-  void
-  onCertificateFetchFailed(const ndn::Name& identity);
-
-  void
-  onWarning(QString msg);
-
-  void
-  onAddClicked();
-
-  void
-  onDirectAddClicked();
-
-public slots:
-  void
-  refreshList();
-
-signals:
-  void
-  newContactAdded();
-
-  void
-  directAddClicked();
-
-private:
-  Ui::BrowseContactDialog *ui;
-  
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-
-  WarningDialog* m_warningDialog;
-  QStringListModel* m_contactListModel;
-
-  QStringList m_contactList;  
-  std::vector<ndn::Name> m_contactNameList;
-  std::vector<ndn::Name> m_certificateNameList;
-  std::map<ndn::Name, ndn::IdentityCertificate> m_certificateMap;
-  std::map<ndn::Name, chronos::Profile> m_profileMap;
-
-  RecLock m_mutex;
-};
-
-#endif // BROWSECONTACTDIALOG_H
diff --git a/src/browsecontactdialog.ui b/src/browsecontactdialog.ui
deleted file mode 100644
index 2c73de9..0000000
--- a/src/browsecontactdialog.ui
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>BrowseContactDialog</class>
- <widget class="QDialog" name="BrowseContactDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>480</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>BrowseContacts</string>
-  </property>
-  <widget class="QWidget" name="layoutWidget">
-   <property name="geometry">
-    <rect>
-     <x>12</x>
-     <y>10</y>
-     <width>581</width>
-     <height>471</height>
-    </rect>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout" stretch="20,1">
-    <item>
-     <layout class="QHBoxLayout" name="horizontalLayout" stretch="2,3">
-      <item>
-       <widget class="QListView" name="ContactList">
-        <property name="contextMenuPolicy">
-         <enum>Qt::CustomContextMenu</enum>
-        </property>
-        <property name="acceptDrops">
-         <bool>false</bool>
-        </property>
-        <property name="editTriggers">
-         <set>QAbstractItemView::NoEditTriggers</set>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTableWidget" name="InfoTable">
-        <attribute name="horizontalHeaderStretchLastSection">
-         <bool>true</bool>
-        </attribute>
-       </widget>
-      </item>
-     </layout>
-    </item>
-    <item>
-     <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
-      <item>
-       <widget class="QPushButton" name="AddButton">
-        <property name="text">
-         <string>Add </string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="DirectAddButton">
-        <property name="text">
-         <string>Direct Add</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/chat-dialog.cpp b/src/chat-dialog.cpp
new file mode 100644
index 0000000..954a4c6
--- /dev/null
+++ b/src/chat-dialog.cpp
@@ -0,0 +1,1174 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *         Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "chat-dialog.h"
+#include "ui_chat-dialog.h"
+
+#include <QScrollBar>
+#include <QMessageBox>
+#include <QCloseEvent>
+
+#ifndef Q_MOC_RUN
+#include <sync-intro-certificate.h>
+#include <boost/random/random_device.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <ndn-cpp-dev/util/random.hpp>
+#include <cryptopp/hex.h>
+#include <cryptopp/files.h>
+#include "logging.h"
+#endif
+
+using namespace std;
+using namespace ndn;
+using namespace chronos;
+
+INIT_LOGGER("ChatDialog");
+
+static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
+static const uint8_t CHRONOS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
+
+Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
+Q_DECLARE_METATYPE(ndn::Data)
+Q_DECLARE_METATYPE(ndn::Interest)
+Q_DECLARE_METATYPE(size_t)
+
+ChatDialog::ChatDialog(ContactManager* contactManager,
+                       shared_ptr<Face> face,
+                       const IdentityCertificate& myCertificate,
+                       const Name& chatroomPrefix,
+		       const Name& localPrefix,
+                       const string& nick,
+                       bool withSecurity,
+		       QWidget* parent) 
+  : QDialog(parent)
+  , ui(new Ui::ChatDialog)
+  , m_contactManager(contactManager)
+  , m_face(face)
+  , m_myCertificate(myCertificate)
+  , m_chatroomName(chatroomPrefix.get(-1).toEscapedString())
+  , m_chatroomPrefix(chatroomPrefix)
+  , m_localPrefix(localPrefix)
+  , m_useRoutablePrefix(false)
+  , m_nick(nick)
+  , m_lastMsgTime(time::now())
+  , m_joined(false)
+  , m_sock(NULL)
+  , m_session(static_cast<uint64_t>(time::now()))
+  , m_inviteListDialog(new InviteListDialog)
+{
+  qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
+  qRegisterMetaType<ndn::Data>("ndn.Data");
+  qRegisterMetaType<ndn::Interest>("ndn.Interest");
+  qRegisterMetaType<size_t>("size_t");
+
+  m_scene = new DigestTreeScene(this);
+  m_rosterModel = new QStringListModel(this);
+  m_timer = new QTimer(this);
+
+  ui->setupUi(this);
+  ui->treeViewer->setScene(m_scene);
+  m_scene->setSceneRect(m_scene->itemsBoundingRect());
+  ui->treeViewer->hide();
+  ui->listView->setModel(m_rosterModel);
+
+  m_identity = IdentityCertificate::certificateNameToPublicKeyName(m_myCertificate.getName()).getPrefix(-1);
+  updatePrefix();
+  updateLabels();
+
+  m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
+  m_scene->plot("Empty");
+
+  connect(ui->lineEdit, SIGNAL(returnPressed()), 
+          this, SLOT(onReturnPressed()));
+  connect(ui->treeButton, SIGNAL(pressed()), 
+          this, SLOT(onTreeButtonPressed()));
+  connect(m_scene, SIGNAL(replot()),
+          this, SLOT(onReplot()));
+  connect(m_scene, SIGNAL(rosterChanged(QStringList)), 
+          this, SLOT(onRosterChanged(QStringList)));
+  connect(m_timer, SIGNAL(timeout()), 
+          this, SLOT(onReplot()));
+
+  connect(this, SIGNAL(processData(const ndn::Data&, bool, bool)), 
+          this, SLOT(onProcessData(const ndn::Data&, bool, bool)));
+  connect(this, SIGNAL(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)), 
+          this, SLOT(onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
+  connect(this, SIGNAL(reply(const ndn::Interest&, const ndn::Data&, size_t, bool)),
+          this, SLOT(onReply(const ndn::Interest&, const ndn::Data&, size_t, bool)));
+  connect(this, SIGNAL(replyTimeout(const ndn::Interest&, size_t)),
+          this, SLOT(onReplyTimeout(const ndn::Interest&, size_t)));
+  connect(this, SIGNAL(introCert(const ndn::Interest&, const ndn::Data&)),
+          this, SLOT(onIntroCert(const ndn::Interest&, const ndn::Data&)));
+  connect(this, SIGNAL(introCertTimeout(const ndn::Interest&, int, const QString&)),
+          this, SLOT(onIntroCertTimeout(const ndn::Interest&, int, const QString&)));
+
+  if(withSecurity)
+    {
+
+      m_invitationValidator = make_shared<chronos::ValidatorInvitation>();
+      m_dataRule = make_shared<SecRuleRelative>("([^<CHRONOCHAT-DATA>]*)<CHRONOCHAT-DATA><>",
+                                                "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
+                                                "==", "\\1", "\\1", true);
+
+      ui->inviteButton->setEnabled(true);
+      connect(ui->inviteButton, SIGNAL(clicked()),
+              this, SLOT(onInviteListDialogRequested()));
+      connect(m_inviteListDialog, SIGNAL(sendInvitation(const QString&)),
+              this, SLOT(onSendInvitation(const QString&)));
+      connect(m_contactManager, SIGNAL(contactAliasListReady(const QStringList&)),
+              m_inviteListDialog, SLOT(onContactAliasListReady(const QStringList&)));
+      connect(m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
+              m_inviteListDialog, SLOT(onContactIdListReady(const QStringList&)));
+    }
+
+  initializeSync();
+}
+
+
+ChatDialog::~ChatDialog()
+{
+  if(m_certListPrefixId)
+    m_face->unsetInterestFilter(m_certListPrefixId);
+
+  if(m_certSinglePrefixId)
+    m_face->unsetInterestFilter(m_certSinglePrefixId);
+
+  if(m_sock != NULL)
+    {
+      sendLeave();
+      delete m_sock;
+      m_sock = NULL;
+    }
+}
+
+// public methods:
+void
+ChatDialog::addSyncAnchor(const Invitation& invitation)
+{
+  // Add inviter certificate as trust anchor.
+  m_sock->addParticipant(invitation.getInviterCertificate());
+
+  // Ask inviter for IntroCertificate
+  Name inviterNameSpace = IdentityCertificate::certificateNameToPublicKeyName(invitation.getInviterCertificate().getName()).getPrefix(-1);
+  fetchIntroCert(inviterNameSpace, invitation.getInviterRoutingPrefix());
+}
+
+void
+ChatDialog::processTreeUpdateWrapper(const vector<Sync::MissingDataInfo>& v, Sync::SyncSocket *sock)
+{
+  emit processTreeUpdate(v);
+  _LOG_DEBUG("<<< Tree update signal emitted");
+}
+
+void
+ChatDialog::processDataWrapper(const shared_ptr<const Data>& data)
+{
+  emit processData(*data, true, false);
+  _LOG_DEBUG("<<< " << data->getName() << " fetched");
+}
+
+void
+ChatDialog::processDataNoShowWrapper(const shared_ptr<const Data>& data)
+{
+  emit processData(*data, false, false);
+}
+
+void
+ChatDialog::processRemoveWrapper(string prefix)
+{
+  _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
+}
+
+// protected methods:
+void
+ChatDialog::closeEvent(QCloseEvent *e)
+{
+  QMessageBox::information(this, tr("ChronoChat"),
+                           tr("The chatroom will keep running in the "
+                              "system tray. To close the chatroom, "
+                              "choose <b>Close chatroom</b> in the "
+                              "context memu of the system tray entry."));
+  hide();
+  e->ignore();
+}
+
+void
+ChatDialog::resizeEvent(QResizeEvent *e)
+{
+  fitView();
+}
+
+void
+ChatDialog::showEvent(QShowEvent *e)
+{
+  fitView();
+}
+
+// private methods:
+void
+ChatDialog::updatePrefix()
+{
+  m_certListPrefix.clear();
+  m_certSinglePrefix.clear();
+  m_localChatPrefix.clear();
+  m_chatPrefix.clear();
+  m_chatPrefix.append(m_identity).append("CHRONOCHAT-DATA").append(m_chatroomName).append(getRandomString());
+  if(!m_localPrefix.isPrefixOf(m_identity))
+    {
+      m_useRoutablePrefix = true;
+      m_certListPrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
+      m_certSinglePrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
+      m_localChatPrefix.append(m_localPrefix).append(CHRONOS_RP_SEPARATOR, 2);
+    }
+  m_certListPrefix.append(m_identity).append("CHRONOCHAT-CERT-LIST").append(m_chatroomName);
+  m_certSinglePrefix.append(m_identity).append("CHRONOCHAT-CERT-SINGLE").append(m_chatroomName);
+  m_localChatPrefix.append(m_chatPrefix);
+
+  if(m_certListPrefixId)
+    m_face->unsetInterestFilter(m_certListPrefixId);
+  m_certListPrefixId = m_face->setInterestFilter (m_certListPrefix, 
+                                                  bind(&ChatDialog::onCertListInterest, this, _1, _2), 
+                                                  bind(&ChatDialog::onCertListRegisterFailed, this, _1, _2));
+
+  if(m_certSinglePrefixId)
+    m_face->unsetInterestFilter(m_certSinglePrefixId);
+  m_certSinglePrefixId = m_face->setInterestFilter (m_certSinglePrefix, 
+                                                    bind(&ChatDialog::onCertSingleInterest, this, _1, _2), 
+                                                    bind(&ChatDialog::onCertSingleRegisterFailed, this, _1, _2));
+}
+
+void
+ChatDialog::updateLabels()
+{
+  QString settingDisp = QString("Chatroom: %1").arg(QString::fromStdString(m_chatroomName));
+  ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
+  ui->infoLabel->setText(settingDisp);
+  QString prefixDisp;
+  Name privatePrefix("/private/local");
+  if(privatePrefix.isPrefixOf(m_localChatPrefix))
+    {
+      prefixDisp = 
+        QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>")
+        .arg(QString::fromStdString(m_localChatPrefix.toUri()));
+      ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
+    }
+  else
+    {
+      prefixDisp = QString("<Prefix = %1>")
+        .arg(QString::fromStdString(m_localChatPrefix.toUri()));
+      ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
+    }
+  ui->prefixLabel->setText(prefixDisp);
+}
+
+void
+ChatDialog::initializeSync()
+{
+  
+  m_sock = new Sync::SyncSocket(m_chatroomPrefix,
+                                m_chatPrefix,
+                                m_session,
+                                m_useRoutablePrefix,
+                                m_localPrefix,
+                                m_face,
+                                m_myCertificate,
+                                m_dataRule,
+                                bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
+                                bind(&ChatDialog::processRemoveWrapper, this, _1));
+  
+  usleep(100000);
+
+  QTimer::singleShot(600, this, SLOT(sendJoin()));
+  m_timer->start(FRESHNESS * 1000);
+  disableTreeDisplay();
+  QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
+}
+
+void
+ChatDialog::sendInvitation(shared_ptr<Contact> contact, bool isIntroducer)
+{
+  // Add invitee as a trust anchor.
+  m_invitationValidator->addTrustAnchor(contact->getPublicKeyName(),
+                                        contact->getPublicKey());
+
+  // Prepared an invitation interest without routable prefix.
+  Invitation invitation(contact->getNameSpace(),
+                        m_chatroomName,
+                        m_localPrefix,
+                        m_myCertificate);
+  Interest tmpInterest(invitation.getUnsignedInterestName());
+  m_keyChain.sign(tmpInterest, m_myCertificate.getName());
+
+  // Get invitee's routable prefix (ideally it will do some DNS lookup, but we assume everyone use /ndn/broadcast
+  Name routablePrefix = getInviteeRoutablePrefix(contact->getNameSpace());
+
+  // Check if we need to prepend the routable prefix to the interest name.
+  bool requireRoutablePrefix = false;
+  Name interestName;
+  size_t routablePrefixOffset = 0;
+  if(!routablePrefix.isPrefixOf(tmpInterest.getName()))
+    {
+      interestName.append(routablePrefix).append(CHRONOS_RP_SEPARATOR, 2);
+      requireRoutablePrefix = true;
+      routablePrefixOffset = routablePrefix.size() + 1;
+    }
+  interestName.append(tmpInterest.getName());
+
+  // Send the invitation out
+  Interest interest(interestName);
+  interest.setMustBeFresh(true);
+  m_face->expressInterest(interest,
+                          bind(&ChatDialog::replyWrapper, this, _1, _2, routablePrefixOffset, isIntroducer),
+                          bind(&ChatDialog::replyTimeoutWrapper, this, _1, routablePrefixOffset));
+}
+
+void
+ChatDialog::replyWrapper(const Interest& interest, 
+                         Data& data,
+                         size_t routablePrefixOffset,
+                         bool isIntroducer)
+{
+  emit reply(interest, data, routablePrefixOffset, isIntroducer);
+}
+
+void
+ChatDialog::replyTimeoutWrapper(const Interest& interest, 
+                                size_t routablePrefixOffset)
+{
+  emit replyTimeout(interest, routablePrefixOffset);
+}
+
+void 
+ChatDialog::onReplyValidated(const shared_ptr<const Data>& data,
+                             size_t inviteeRoutablePrefixOffset,
+                             bool isIntroducer)
+{
+  if(data->getName().size() <= inviteeRoutablePrefixOffset)
+    {
+      Invitation invitation(data->getName());
+      invitationRejected(invitation.getInviteeNameSpace());
+    }
+  else
+    {
+      Name inviteePrefix;
+      inviteePrefix.wireDecode(data->getName().get(inviteeRoutablePrefixOffset).blockFromValue());
+      IdentityCertificate inviteeCert;
+      inviteeCert.wireDecode(data->getContent().blockFromValue());
+      invitationAccepted(inviteeCert, inviteePrefix, isIntroducer);
+    }
+}
+
+void
+ChatDialog::onReplyValidationFailed(const shared_ptr<const Data>& data,
+                                    const string& failureInfo)
+{
+  _LOG_DEBUG("Invitation reply cannot be validated: " + failureInfo + " ==> " + data->getName().toUri());
+}
+
+void
+ChatDialog::invitationRejected(const Name& identity)
+{
+  QString msg = QString::fromStdString(identity.toUri()) + " rejected your invitation!";
+  emit inivationRejection(msg);
+}
+
+void
+ChatDialog::invitationAccepted(const IdentityCertificate& inviteeCert, 
+                               const Name& inviteePrefix, 
+                               bool isIntroducer)
+{
+  // Add invitee certificate as trust anchor.
+  m_sock->addParticipant(inviteeCert);
+
+  // Ask invitee for IntroCertificate.
+  Name inviteeNameSpace = IdentityCertificate::certificateNameToPublicKeyName(inviteeCert.getName()).getPrefix(-1);
+  fetchIntroCert(inviteeNameSpace, inviteePrefix);
+}
+
+void
+ChatDialog::fetchIntroCert(const Name& identity, const Name& prefix)
+{
+  Name interestName;
+
+  if(!prefix.isPrefixOf(identity))
+    interestName.append(prefix).append(CHRONOS_RP_SEPARATOR, 2);
+  
+  interestName.append(identity)
+    .append("CHRONOCHAT-CERT-LIST")
+    .append(m_chatroomName)
+    .appendVersion();
+
+  Interest interest(interestName);
+  interest.setMustBeFresh(true);
+
+  m_face->expressInterest(interest,
+                          bind(&ChatDialog::onIntroCertList, this, _1, _2),
+                          bind(&ChatDialog::onIntroCertListTimeout, this, _1, 1, 
+                               "IntroCertList: " + interestName.toUri()));
+}
+
+void
+ChatDialog::onIntroCertList(const Interest& interest, const Data& data)
+{
+  Chronos::IntroCertListMsg introCertList;
+  if(!introCertList.ParseFromArray(data.getContent().value(), data.getContent().value_size()))
+    return;
+
+  for(int i = 0; i < introCertList.certname_size(); i++)
+    {
+      Name certName(introCertList.certname(i));
+      Interest interest(certName);
+      interest.setMustBeFresh(true);
+
+      m_face->expressInterest(interest,
+                              bind(&ChatDialog::introCertWrapper, this, _1, _2),
+                              bind(&ChatDialog::introCertTimeoutWrapper, this, _1, 0, 
+                                   QString("IntroCert: %1").arg(introCertList.certname(i).c_str())));
+    }  
+}
+
+void
+ChatDialog::onIntroCertListTimeout(const Interest& interest, int retry, const string& msg)
+{
+  if(retry > 0)
+    m_face->expressInterest(interest,
+                            bind(&ChatDialog::onIntroCertList, this, _1, _2),
+                            bind(&ChatDialog::onIntroCertListTimeout, this, _1, retry - 1, msg));
+  else
+    _LOG_DEBUG(msg << " TIMEOUT!");
+}
+
+void
+ChatDialog::introCertWrapper(const Interest& interest, Data& data)
+{
+  emit introCert(interest, data);
+}
+
+void
+ChatDialog::introCertTimeoutWrapper(const Interest& interest, int retry, const QString& msg)
+{
+  emit introCertTimeout(interest, retry, msg);
+}
+
+void
+ChatDialog::onCertListInterest(const Name& prefix, const ndn::Interest& interest)
+{
+  vector<Name> certNameList;
+  m_sock->getIntroCertNames(certNameList);
+
+  Chronos::IntroCertListMsg msg;
+
+  vector<Name>::const_iterator it = certNameList.begin();
+  vector<Name>::const_iterator end = certNameList.end();
+  for(; it != end; it++)
+    {
+      Name certName;
+      certName.append(m_certSinglePrefix).append(*it);
+      msg.add_certname(certName.toUri());
+    }
+  OBufferStream os;
+  msg.SerializeToOstream(&os);
+
+  Data data(interest.getName());
+  data.setContent(os.buf());
+  m_keyChain.sign(data, m_myCertificate.getName());
+
+  m_face->put(data);
+}
+
+void
+ChatDialog::onCertListRegisterFailed(const Name& prefix, const string& msg)
+{
+  _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
+}
+
+void
+ChatDialog::onCertSingleInterest(const Name& prefix, const ndn::Interest& interest)
+{
+  try
+    {
+      Name certName = interest.getName().getSubName(prefix.size());
+      const Sync::IntroCertificate& introCert = m_sock->getIntroCertificate(certName);
+      Data data(interest.getName());
+      data.setContent(introCert.wireEncode());
+      m_face->put(data);
+    }
+  catch(Sync::SyncSocket::Error& e)
+    {
+      return;
+    }
+}
+
+void
+ChatDialog::onCertSingleRegisterFailed(const Name& prefix, const string& msg)
+{
+  _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
+}
+
+void
+ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
+{
+  // send msg
+  OBufferStream os;
+  msg.SerializeToOstream(&os);
+  
+  if (!msg.IsInitialized())
+  {
+    _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
+    abort();
+  }
+  m_sock->publishData(os.buf()->buf(), os.buf()->size(), FRESHNESS);
+
+  m_lastMsgTime = time::now();
+
+  uint64_t nextSequence = m_sock->getNextSeq();
+  Sync::MissingDataInfo mdi = {m_localChatPrefix.toUri(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
+  std::vector<Sync::MissingDataInfo> v;
+  v.push_back(mdi);
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
+    m_scene->msgReceived(QString::fromStdString(m_localChatPrefix.toUri()),
+                         QString::fromStdString(m_nick));
+  }
+}
+
+void ChatDialog::disableTreeDisplay()
+{
+  ui->treeButton->setEnabled(false);
+  ui->treeViewer->hide();
+  fitView();
+}
+
+void
+ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
+{
+  boost::recursive_mutex::scoped_lock lock(m_msgMutex);
+
+  if (msg.type() == SyncDemo::ChatMessage::CHAT)
+  {
+
+    if (!msg.has_data())
+    {
+      return;
+    }
+
+    if (msg.from().empty() || msg.data().empty())
+    {
+      return;
+    }
+
+    if (!msg.has_timestamp())
+    {
+      return;
+    }
+
+    // if (m_history.size() == MAX_HISTORY_ENTRY)
+    // {
+    //   m_history.dequeue();
+    // }
+
+    // m_history.enqueue(msg);
+
+    QTextCharFormat nickFormat;
+    nickFormat.setForeground(Qt::darkGreen);
+    nickFormat.setFontWeight(QFont::Bold);
+    nickFormat.setFontUnderline(true);
+    nickFormat.setUnderlineColor(Qt::gray);
+
+    QTextCursor cursor(ui->textEdit->textCursor());
+    cursor.movePosition(QTextCursor::End);
+    QTextTableFormat tableFormat;
+    tableFormat.setBorder(0);
+    QTextTable *table = cursor.insertTable(1, 2, tableFormat);
+    QString from = QString("%1 ").arg(msg.from().c_str());
+    QTextTableCell fromCell = table->cellAt(0, 0);
+    fromCell.setFormat(nickFormat);
+    fromCell.firstCursorPosition().insertText(from);
+
+    time_t timestamp = msg.timestamp();
+    printTimeInCell(table, timestamp);
+
+    QTextCursor nextCursor(ui->textEdit->textCursor());
+    nextCursor.movePosition(QTextCursor::End);
+    table = nextCursor.insertTable(1, 1, tableFormat);
+    table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
+    if (!isHistory)
+    {
+      showMessage(from, QString::fromUtf8(msg.data().c_str()));
+    }
+  }
+
+  if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
+  {
+    QTextCharFormat nickFormat;
+    nickFormat.setForeground(Qt::gray);
+    nickFormat.setFontWeight(QFont::Bold);
+    nickFormat.setFontUnderline(true);
+    nickFormat.setUnderlineColor(Qt::gray);
+
+    QTextCursor cursor(ui->textEdit->textCursor());
+    cursor.movePosition(QTextCursor::End);
+    QTextTableFormat tableFormat;
+    tableFormat.setBorder(0);
+    QTextTable *table = cursor.insertTable(1, 2, tableFormat);
+    QString action;
+    if (msg.type() == SyncDemo::ChatMessage::JOIN)
+    {
+      action = "enters room";
+    }
+    else
+    {
+      action = "leaves room";
+    }
+
+    QString from = QString("%1 %2  ").arg(msg.from().c_str()).arg(action);
+    QTextTableCell fromCell = table->cellAt(0, 0);
+    fromCell.setFormat(nickFormat);
+    fromCell.firstCursorPosition().insertText(from);
+
+    time_t timestamp = msg.timestamp();
+    printTimeInCell(table, timestamp);
+  }
+
+  QScrollBar *bar = ui->textEdit->verticalScrollBar();
+  bar->setValue(bar->maximum());
+}
+
+void
+ChatDialog::processRemove(QString prefix)
+{
+  _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
+
+  bool removed = m_scene->removeNode(prefix);
+  if (removed)
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_scene->plot(m_sock->getRootDigest().c_str());
+  }
+}
+
+Name
+ChatDialog::getInviteeRoutablePrefix(const Name& invitee)
+{
+  return ndn::Name("/ndn/broadcast");
+}
+
+void
+ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
+  msg.set_from(m_nick);
+  msg.set_to(m_chatroomName);
+  msg.set_data(text.toStdString());
+  int32_t seconds = static_cast<int32_t>(time::now()/1000000000);
+  msg.set_timestamp(seconds);
+  msg.set_type(SyncDemo::ChatMessage::CHAT);
+}
+
+void
+ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
+{
+  msg.set_from(m_nick);
+  msg.set_to(m_chatroomName);
+  int32_t seconds = static_cast<int32_t>(time::now()/1000000000);
+  msg.set_timestamp(seconds);
+  msg.set_type(type);
+}
+
+QString
+ChatDialog::formatTime(time_t timestamp)
+{
+  struct tm *tm_time = localtime(&timestamp);
+  int hour = tm_time->tm_hour;
+  QString amOrPM;
+  if (hour > 12)
+  {
+    hour -= 12;
+    amOrPM = "PM";
+  }
+  else
+  {
+    amOrPM = "AM";
+    if (hour == 0)
+    {
+      hour = 12;
+    }
+  }
+
+  char textTime[12];
+  sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
+  return QString(textTime);
+}
+
+void
+ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
+{
+  QTextCharFormat timeFormat;
+  timeFormat.setForeground(Qt::gray);
+  timeFormat.setFontUnderline(true);
+  timeFormat.setUnderlineColor(Qt::gray);
+  QTextTableCell timeCell = table->cellAt(0, 1);
+  timeCell.setFormat(timeFormat);
+  timeCell.firstCursorPosition().insertText(formatTime(timestamp));
+}
+
+string
+ChatDialog::getRandomString()
+{
+  uint32_t r = random::generateWord32();
+  stringstream ss;
+  {
+    using namespace CryptoPP;
+    StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
+                 new HexEncoder(new FileSink(ss), false));
+    
+  }
+
+  return ss.str();
+}
+
+void
+ChatDialog::showMessage(const QString& from, const QString& data)
+{
+  if (!isActiveWindow())
+    emit showChatMessage(QString::fromStdString(m_chatroomName),
+                         from, data);
+}
+
+void
+ChatDialog::fitView()
+{
+  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+  QRectF rect = m_scene->itemsBoundingRect();
+  m_scene->setSceneRect(rect);
+  ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
+}
+
+void
+ChatDialog::summonReaper()
+{
+  Sync::SyncLogic &logic = m_sock->getLogic ();
+  map<string, bool> branches = logic.getBranchPrefixes();
+  QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
+
+  m_zombieList.clear();
+
+  QMapIterator<QString, DisplayUserPtr> it(roster);
+  map<string, bool>::iterator mapIt;
+  while(it.hasNext())
+  {
+    it.next();
+    DisplayUserPtr p = it.value();
+    if (p != DisplayUserNullPtr)
+    {
+      mapIt = branches.find(p->getPrefix().toStdString());
+      if (mapIt != branches.end())
+      {
+        mapIt->second = true;
+      }
+    }
+  }
+
+  for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
+  {
+    // this is zombie. all active users should have been marked true
+    if (! mapIt->second)
+    {
+      m_zombieList.append(mapIt->first.c_str());
+    }
+  }
+
+  m_zombieIndex = 0;
+
+  // start reaping
+  reap();
+}
+
+
+// public slots:
+void
+ChatDialog::onLocalPrefixUpdated(const QString& localPrefix)
+{
+  Name newLocalPrefix(localPrefix.toStdString());
+  if(!newLocalPrefix.empty() && newLocalPrefix != m_localPrefix) 
+    {
+      // Update localPrefix
+      m_localPrefix = newLocalPrefix;
+
+      updatePrefix();
+      updateLabels();
+      m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
+
+      if(m_sock != NULL)
+        {
+          {
+            boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+            m_scene->clearAll();
+            m_scene->plot("Empty");
+          }
+
+          ui->textEdit->clear();
+          
+          if (m_joined)
+            {
+              sendLeave();
+            }
+
+          delete m_sock;
+          m_sock = NULL;
+          
+          usleep(100000);
+          m_sock = new Sync::SyncSocket(m_chatroomPrefix,
+                                        m_chatPrefix,
+                                        m_session,
+                                        m_useRoutablePrefix,
+                                        m_localPrefix,
+                                        m_face,
+                                        m_myCertificate,
+                                        m_dataRule,
+                                        bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
+                                        bind(&ChatDialog::processRemoveWrapper, this, _1));
+          usleep(100000);
+          QTimer::singleShot(600, this, SLOT(sendJoin()));
+          m_timer->start(FRESHNESS * 1000);
+          disableTreeDisplay();
+          QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
+        }
+      else
+        initializeSync();
+    }
+  else 
+    if (m_sock == NULL)
+      initializeSync();
+
+  fitView();
+}
+
+void
+ChatDialog::onClose()
+{
+  hide();
+  emit closeChatDialog(QString::fromStdString(m_chatroomName));
+}
+
+
+// private slots:
+void
+ChatDialog::onReturnPressed()
+{
+  QString text = ui->lineEdit->text();
+  if (text.isEmpty())
+    return;
+
+  ui->lineEdit->clear();
+
+  if (text.startsWith("boruoboluomi"))
+  {
+    summonReaper ();
+    // reapButton->show();
+    fitView();
+    return;
+  }
+
+  if (text.startsWith("minimanihong"))
+  {
+    // reapButton->hide();
+    fitView();
+    return;
+  }
+
+  SyncDemo::ChatMessage msg;
+  formChatMessage(text, msg);
+
+  appendMessage(msg);
+
+  sendMsg(msg);
+
+  fitView();
+}
+
+void 
+ChatDialog::onTreeButtonPressed()
+{
+  if (ui->treeViewer->isVisible())
+  {
+    ui->treeViewer->hide();
+    ui->treeButton->setText("Show ChronoSync Tree");
+  }
+  else
+  {
+    ui->treeViewer->show();
+    ui->treeButton->setText("Hide ChronoSync Tree");
+  }
+
+  fitView();
+}
+
+void
+ChatDialog::onProcessData(const Data& data, bool show, bool isHistory)
+{
+  SyncDemo::ChatMessage msg;
+  bool corrupted = false;
+  if (!msg.ParseFromArray(data.getContent().value(), data.getContent().value_size()))
+  {
+    _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << data.getName() << ". what is happening?");
+    // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
+    msg.set_from("inconnu");
+    msg.set_type(SyncDemo::ChatMessage::OTHER);
+    corrupted = true;
+  }
+
+  // display msg received from network
+  // we have to do so; this function is called by ccnd thread
+  // so if we call appendMsg directly
+  // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
+  // the "cannonical" way to is use signal-slot
+  if (show && !corrupted)
+  {
+    appendMessage(msg, isHistory);
+  }
+
+  if (!isHistory)
+  {
+    // update the tree view
+    std::string stdStrName = data.getName().toUri();
+    std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
+    std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
+    _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
+    if (msg.type() == SyncDemo::ChatMessage::LEAVE)
+    {
+      processRemove(prefix.c_str());
+    }
+    else
+    {
+      boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+      m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
+    }
+  }
+  fitView();
+}
+
+void
+ChatDialog::onProcessTreeUpdate(const vector<Sync::MissingDataInfo>& v)
+{
+  _LOG_DEBUG("<<< processing Tree Update");
+
+  if (v.empty())
+  {
+    return;
+  }
+
+  // reflect the changes on digest tree
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
+  }
+
+  int n = v.size();
+  int totalMissingPackets = 0;
+  for (int i = 0; i < n; i++)
+  {
+    totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
+  }
+
+  for (int i = 0; i < n; i++)
+  {
+    if (totalMissingPackets < 4)
+    {
+      for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
+      {
+        m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
+        _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
+      }
+    }
+    else
+    {
+        m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
+    }
+  }
+  // adjust the view
+  fitView();
+}
+
+void
+ChatDialog::onReplot()
+{
+  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+  m_scene->plot(m_sock->getRootDigest().c_str());
+  fitView();
+}
+
+void
+ChatDialog::onRosterChanged(QStringList staleUserList)
+{
+  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+  QStringList rosterList = m_scene->getRosterList();
+  m_rosterModel->setStringList(rosterList);
+  QString user;
+  QStringListIterator it(staleUserList);
+  while(it.hasNext())
+  {
+    std::string nick = it.next().toStdString();
+    if (nick.empty())
+      continue;
+
+    SyncDemo::ChatMessage msg;
+    formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
+    msg.set_from(nick);
+    appendMessage(msg);
+  }
+}
+
+void
+ChatDialog::onInviteListDialogRequested()
+{
+  m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
+  m_inviteListDialog->show();
+}
+
+void
+ChatDialog::sendJoin()
+{
+  m_joined = true;
+  SyncDemo::ChatMessage msg;
+  formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
+  sendMsg(msg);
+  boost::random::random_device rng;
+  boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
+  m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
+  QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
+}
+
+void
+ChatDialog::sendHello()
+{
+  int64_t now = time::now();
+  int elapsed = (now - m_lastMsgTime) / 1000000000;
+  if (elapsed >= m_randomizedInterval / 1000)
+  {
+    SyncDemo::ChatMessage msg;
+    formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
+    sendMsg(msg);
+    boost::random::random_device rng;
+    boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
+    m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
+    QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
+  }
+  else
+  {
+    QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
+  }
+}
+
+void
+ChatDialog::sendLeave()
+{
+  SyncDemo::ChatMessage msg;
+  formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
+  sendMsg(msg);
+  usleep(500000);
+  m_sock->leave();
+  usleep(5000);
+  m_joined = false;
+  _LOG_DEBUG("Sync REMOVE signal sent");
+}
+
+void ChatDialog::enableTreeDisplay()
+{
+  ui->treeButton->setEnabled(true);
+  // treeViewer->show();
+  // fitView();
+}
+
+void
+ChatDialog::reap()
+{
+  if (m_zombieIndex < m_zombieList.size())
+  {
+    string prefix = m_zombieList.at(m_zombieIndex).toStdString();
+    m_sock->remove(prefix);
+    _LOG_DEBUG("Reaped: prefix = " << prefix);
+    m_zombieIndex++;
+    // reap again in 10 seconds
+    QTimer::singleShot(10000, this, SLOT(reap()));
+  }
+}
+
+void
+ChatDialog::onSendInvitation(QString invitee)
+{
+  Name inviteeNamespace(invitee.toStdString());
+  shared_ptr<Contact> inviteeItem = m_contactManager->getContact(inviteeNamespace);
+  sendInvitation(inviteeItem, true);
+}
+
+void 
+ChatDialog::onReply(const Interest& interest, 
+                    const Data& data,
+                    size_t routablePrefixOffset,
+                    bool isIntroducer)
+{
+  OnDataValidated onValidated = bind(&ChatDialog::onReplyValidated,
+                                     this, _1, 
+                                     interest.getName().size()-routablePrefixOffset, //RoutablePrefix will be removed before data is passed to the validator
+                                     isIntroducer);
+
+  OnDataValidationFailed onFailed = bind(&ChatDialog::onReplyValidationFailed,
+                                         this, _1, _2);
+
+  if(routablePrefixOffset > 0)
+    {
+      // It is an encapsulated packet, we only validate the inner packet.
+      Data innerData;
+      innerData.wireDecode(data.getContent().blockFromValue());
+      m_invitationValidator->validate(innerData, onValidated, onFailed);
+    }
+  else
+    m_invitationValidator->validate(data, onValidated, onFailed);
+}
+
+void
+ChatDialog::onReplyTimeout(const Interest& interest, 
+                           size_t routablePrefixOffset)
+{
+  Name interestName;
+  if(routablePrefixOffset > 0)
+    interestName = interest.getName().getSubName(routablePrefixOffset);
+  else
+    interestName = interest.getName();
+
+  Invitation invitation(interestName);
+
+  QString msg = QString::fromUtf8("Your invitation to ") + QString::fromStdString(invitation.getInviteeNameSpace().toUri()) + " times out!";
+  emit inivationRejection(msg);
+}
+
+void
+ChatDialog::onIntroCert(const ndn::Interest& interest, const Data& data)
+{
+  Data innerData;
+  innerData.wireDecode(data.getContent().blockFromValue());
+  Sync::IntroCertificate introCert(innerData);
+  m_sock->addParticipant(introCert);
+}
+
+void
+ChatDialog::onIntroCertTimeout(const ndn::Interest& interest, int retry, const QString& msg)
+{
+  _LOG_DEBUG("onIntroCertTimeout: " << msg.toStdString());
+}
+
+
+
+#if WAF
+#include "chat-dialog.moc"
+#include "chat-dialog.cpp.moc"
+#endif
diff --git a/src/chat-dialog.h b/src/chat-dialog.h
new file mode 100644
index 0000000..f136b82
--- /dev/null
+++ b/src/chat-dialog.h
@@ -0,0 +1,329 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *         Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHAT_DIALOG_H
+#define CHAT_DIALOG_H
+
+#include <QDialog>
+#include <QTextTable>
+#include <QStringListModel>
+#include <QSystemTrayIcon>
+#include <QMenu>
+#include <QTimer>
+
+#include "invite-list-dialog.h"
+
+#ifndef Q_MOC_RUN
+#include "contact-manager.h"
+#include "invitation.h"
+#include "contact.h"
+#include "chatbuf.pb.h"
+#include "intro-cert-list.pb.h"
+#include "digesttreescene.h"
+#include <sync-socket.h>
+#include <sync-seq-no.h>
+#include <ndn-cpp-dev/security/key-chain.hpp>
+#include "validator-invitation.h"
+
+#include <boost/thread/locks.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#endif
+
+#define MAX_HISTORY_ENTRY   20
+
+namespace Ui {
+class ChatDialog;
+}
+
+class ChatDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit 
+  ChatDialog(chronos::ContactManager* contactManager,
+             ndn::shared_ptr<ndn::Face> face,
+             const ndn::IdentityCertificate& myCertificate,
+             const ndn::Name& chatroomPrefix,
+             const ndn::Name& localPrefix,
+             const std::string& nick,
+             bool witSecurity,
+             QWidget* parent = 0);
+
+  ~ChatDialog();
+  
+  void 
+  addSyncAnchor(const chronos::Invitation& invitation);
+
+  void 
+  processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>&, Sync::SyncSocket *);
+
+  void 
+  processDataWrapper(const ndn::shared_ptr<const ndn::Data>& data);
+
+  void 
+  processDataNoShowWrapper(const ndn::shared_ptr<const ndn::Data>& data);
+
+  void 
+  processRemoveWrapper(std::string);
+
+protected:
+  void 
+  closeEvent(QCloseEvent *e);
+
+  void 
+  resizeEvent(QResizeEvent *);
+  
+  void 
+  showEvent(QShowEvent *);
+
+private:
+  void
+  updatePrefix();
+  
+  void 
+  updateLabels();
+
+  void
+  initializeSync();
+
+  void
+  sendInvitation(ndn::shared_ptr<chronos::Contact> contact, bool isIntroducer);
+
+  void 
+  replyWrapper(const ndn::Interest& interest, 
+               ndn::Data& data,
+               size_t routablePrefixOffset,
+               bool isIntroducer);
+
+  void 
+  replyTimeoutWrapper(const ndn::Interest& interest,
+                      size_t routablePrefixOffset);
+
+  void 
+  onReplyValidated(const ndn::shared_ptr<const ndn::Data>& data,
+                   size_t inviteeRoutablePrefixOffset,
+                   bool isIntroduce);
+
+  void
+  onReplyValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
+                          const std::string& failureInfo);
+
+  void
+  invitationRejected(const ndn::Name& identity);
+  
+  void 
+  invitationAccepted(const ndn::IdentityCertificate& inviteeCert,
+                     const ndn::Name& inviteePrefix, 
+                     bool isIntroducer);
+
+  void
+  fetchIntroCert(const ndn::Name& identity, const ndn::Name& prefix);
+
+  void
+  onIntroCertList(const ndn::Interest& interest, const ndn::Data& data);
+
+  void
+  onIntroCertListTimeout(const ndn::Interest& interest, int retry, const std::string& msg);
+
+  void
+  introCertWrapper(const ndn::Interest& interest, ndn::Data& data);
+  
+  void
+  introCertTimeoutWrapper(const ndn::Interest& interest, int retry, const QString& msg);
+
+  void
+  onCertListInterest(const ndn::Name& prefix, const ndn::Interest& interest);
+
+  void
+  onCertListRegisterFailed(const ndn::Name& prefix, const std::string& msg);
+
+  void
+  onCertSingleInterest(const ndn::Name& prefix, const ndn::Interest& interest);
+
+  void
+  onCertSingleRegisterFailed(const ndn::Name& prefix, const std::string& msg);
+
+
+  void 
+  sendMsg(SyncDemo::ChatMessage &msg);
+
+  void 
+  disableTreeDisplay();
+
+  void 
+  appendMessage(const SyncDemo::ChatMessage msg, bool isHistory = false);
+
+  void 
+  processRemove(QString prefix);
+
+  ndn::Name
+  getInviteeRoutablePrefix(const ndn::Name& invitee);
+
+  void 
+  formChatMessage(const QString &text, SyncDemo::ChatMessage &msg);
+
+  void 
+  formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type);
+
+  QString 
+  formatTime(time_t);
+
+  void 
+  printTimeInCell(QTextTable *, time_t);
+
+  std::string 
+  getRandomString();
+
+  void 
+  showMessage(const QString&, const QString&);
+
+  void 
+  fitView();
+
+  void 
+  summonReaper();
+
+signals:  
+  void
+  processData(const ndn::Data& data, bool show, bool isHistory);
+
+  void 
+  processTreeUpdate(const std::vector<Sync::MissingDataInfo>);
+
+  void
+  closeChatDialog(const QString& chatroomName);
+
+  void
+  inivationRejection(const QString& msg);
+             
+  void
+  showChatMessage(const QString& chatroomName, const QString& from, const QString& data);
+
+  void
+  reply(const ndn::Interest& interest, const ndn::Data& data, size_t routablePrefixOffset, bool isIntroducer);
+
+  void
+  replyTimeout(const ndn::Interest& interest, size_t routablePrefixOffset);
+
+  void
+  introCert(const ndn::Interest& interest, const ndn::Data& data);
+  
+  void
+  introCertTimeout(const ndn::Interest& interest, int retry, const QString& msg);
+
+
+public slots:
+  void
+  onLocalPrefixUpdated(const QString& localPrefix);
+
+  void
+  onClose();
+
+private slots:
+  void
+  onReturnPressed();
+
+  void 
+  onTreeButtonPressed();
+
+  void 
+  onProcessData(const ndn::Data& data, bool show, bool isHistory);
+
+  void 
+  onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>&);
+
+  void 
+  onReplot();
+
+  void 
+  onRosterChanged(QStringList);
+
+  void
+  onInviteListDialogRequested();
+
+  void 
+  sendJoin();
+
+  void
+  sendHello();
+
+  void
+  sendLeave();
+
+  void 
+  enableTreeDisplay();
+
+  void
+  reap();
+
+  void
+  onSendInvitation(QString);
+
+  void
+  onReply(const ndn::Interest& interest, const ndn::Data& data, size_t routablePrefixOffset, bool isIntroducer);
+
+  void
+  onReplyTimeout(const ndn::Interest& interest, size_t routablePrefixOffset);
+
+  void
+  onIntroCert(const ndn::Interest& interest, const ndn::Data& data);
+
+  void
+  onIntroCertTimeout(const ndn::Interest& interest, int retry, const QString& msg);
+
+private:
+  Ui::ChatDialog *ui;
+  ndn::KeyChain m_keyChain;
+
+  chronos::ContactManager* m_contactManager;
+  ndn::shared_ptr<ndn::Face> m_face;
+
+  ndn::IdentityCertificate m_myCertificate;
+  ndn::Name m_identity;
+
+  ndn::Name m_certListPrefix;
+  const ndn::RegisteredPrefixId* m_certListPrefixId;
+  ndn::Name m_certSinglePrefix;
+  const ndn::RegisteredPrefixId* m_certSinglePrefixId;
+
+  std::string m_chatroomName;
+  ndn::Name m_chatroomPrefix;
+  ndn::Name m_localPrefix;
+  bool m_useRoutablePrefix;
+  ndn::Name m_chatPrefix;
+  ndn::Name m_localChatPrefix;
+  std::string m_nick;
+  DigestTreeScene *m_scene;
+  QStringListModel *m_rosterModel;
+  QTimer* m_timer;
+
+
+  int64_t m_lastMsgTime;
+  int m_randomizedInterval;
+  bool m_joined;
+
+  Sync::SyncSocket *m_sock;
+  uint64_t m_session;
+  ndn::shared_ptr<ndn::SecRuleRelative> m_dataRule;
+
+  InviteListDialog* m_inviteListDialog;
+  ndn::shared_ptr<chronos::ValidatorInvitation> m_invitationValidator;
+
+  boost::recursive_mutex m_msgMutex;
+  boost::recursive_mutex m_sceneMutex;
+  QList<QString> m_zombieList;
+  int m_zombieIndex;
+};
+
+#endif // CHAT_DIALOG_H
diff --git a/src/chatdialog.ui b/src/chat-dialog.ui
similarity index 90%
rename from src/chatdialog.ui
rename to src/chat-dialog.ui
index 256aadf..2d174c0 100644
--- a/src/chatdialog.ui
+++ b/src/chat-dialog.ui
@@ -18,12 +18,12 @@
     <number>6</number>
    </property>
    <item>
-    <layout class="QHBoxLayout">
+    <layout class="QHBoxLayout" name="horizontalLayout">
      <property name="spacing">
       <number>-1</number>
      </property>
      <item>
-      <layout class="QVBoxLayout">
+      <layout class="QVBoxLayout" name="infoLayout">
        <item>
         <widget class="QLabel" name="infoLabel">
          <property name="focusPolicy">
@@ -32,7 +32,7 @@
         </widget>
        </item>
        <item>
-        <layout class="QHBoxLayout">
+        <layout class="QHBoxLayout" name="prefixLayout">
          <item>
           <widget class="QLabel" name="prefixLabel">
            <property name="focusPolicy">
@@ -58,12 +58,15 @@
       </spacer>
      </item>
      <item>
-      <layout class="QVBoxLayout">
+      <layout class="QVBoxLayout" name="buttonLayout">
        <property name="sizeConstraint">
         <enum>QLayout::SetFixedSize</enum>
        </property>
        <item>
         <widget class="QPushButton" name="inviteButton">
+         <property name="enabled">
+          <bool>false</bool>
+         </property>
          <property name="text">
           <string>Invite</string>
          </property>
@@ -108,7 +111,7 @@
     </layout>
    </item>
    <item>
-    <layout class="QHBoxLayout">
+    <layout class="QHBoxLayout" name="chatLayout_2">
      <item>
       <widget class="QListView" name="listView">
        <property name="sizePolicy">
@@ -143,7 +146,7 @@
       </widget>
      </item>
      <item>
-      <layout class="QVBoxLayout">
+      <layout class="QVBoxLayout" name="messageLayout">
        <item>
         <widget class="QGraphicsView" name="treeViewer">
          <property name="focusPolicy">
@@ -162,7 +165,7 @@
         </widget>
        </item>
        <item>
-        <layout class="QHBoxLayout">
+        <layout class="QHBoxLayout" name="inputLayout">
          <item>
           <widget class="QLabel" name="label">
            <property name="text">
diff --git a/src/chatdialog.cpp b/src/chatdialog.cpp
deleted file mode 100644
index 6603183..0000000
--- a/src/chatdialog.cpp
+++ /dev/null
@@ -1,1172 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
- *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
- *         Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "chatdialog.h"
-#include "ui_chatdialog.h"
-
-#include <QScrollBar>
-#include <QMessageBox>
-#include <QCloseEvent>
-
-#ifndef Q_MOC_RUN
-#include "invitation.h"
-
-#ifdef WITH_SECURITY
-#include <sync-intro-certificate.h>
-#endif
-
-#include <boost/random/random_device.hpp>
-#include <boost/random/uniform_int_distribution.hpp>
-#include <ndn-cpp-dev/security/signature-sha256-with-rsa.hpp>
-#include "logging.h"
-#endif
-
-using namespace std;
-using namespace ndn;
-using namespace chronos;
-
-INIT_LOGGER("ChatDialog");
-
-static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
-
-Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
-Q_DECLARE_METATYPE(ndn::shared_ptr<const ndn::Data> )
-Q_DECLARE_METATYPE(size_t)
-
-ChatDialog::ChatDialog(shared_ptr<ContactManager> contactManager,
-                       shared_ptr<Face> face,
-                       const Name& chatroomPrefix,
-		       const Name& localPrefix,
-                       const Name& defaultIdentity,
-                       const string& nick,
-		       QWidget *parent) 
-  : QDialog(parent)
-  , ui(new Ui::ChatDialog)
-  , m_contactManager(contactManager)
-  , m_face(face)
-  , m_ioService(face->ioService())
-  , m_chatroomPrefix(chatroomPrefix)
-  , m_localPrefix(localPrefix)
-  , m_defaultIdentity(defaultIdentity)
-  , m_nick(nick)
-  , m_scheduler(*face->ioService())
-  , m_keyChain(new KeyChain())
-  , m_sock(NULL)
-  , m_lastMsgTime(time::now())
-  , m_joined(false)
-  , m_inviteListDialog(new InviteListDialog(m_contactManager))
-{
-  qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
-  qRegisterMetaType<ndn::shared_ptr<const ndn::Data> >("ndn::shared_ptr<const ndn::Data>");
-  qRegisterMetaType<size_t>("size_t");
-
-  ui->setupUi(this);
-
-  QString randString = getRandomString();
-  m_localChatPrefix = m_localPrefix;
-  m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
-  m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
-
-  m_session = static_cast<uint64_t>(time::now());
-  m_scene = new DigestTreeScene(m_ioService, this);
-
-  initializeSetting();
-  updateLabels();
-
-  ui->treeViewer->setScene(m_scene);
-  ui->treeViewer->hide();
-  m_scene->plot("Empty");
-  QRectF rect = m_scene->itemsBoundingRect();
-  m_scene->setSceneRect(rect);
-
-  m_rosterModel = new QStringListModel(this);
-  ui->listView->setModel(m_rosterModel);
-
-  createActions();
-  createTrayIcon();
-
-#ifndef SECURITY
-  m_invitationValidator = make_shared<ValidatorNull>();
-  m_syncValidator = make_shared<ValidatorNull>();
-#else
-  m_invitationValidator = make_shared<chronos::ValidatorInvitation>();
-  m_syncValidator = ...;
-#endif
-
-  connect(ui->inviteButton, SIGNAL(clicked()),
-          this, SLOT(openInviteListDialog()));
-  connect(m_inviteListDialog, SIGNAL(invitionDetermined(QString, bool)),
-          this, SLOT(sendInvitationWrapper(QString, bool)));
-  connect(ui->lineEdit, SIGNAL(returnPressed()), 
-          this, SLOT(returnPressed()));
-  connect(ui->treeButton, SIGNAL(pressed()), 
-          this, SLOT(treeButtonPressed()));
-  connect(this, SIGNAL(dataReceived(ndn::shared_ptr<const ndn::Data>, bool, bool)), 
-          this, SLOT(processData(ndn::shared_ptr<const ndn::Data>, bool, bool)));
-  connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), 
-          this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
-  connect(m_scene, SIGNAL(replot()), 
-          this, SLOT(replot()));
-  connect(trayIcon, SIGNAL(messageClicked()), 
-          this, SLOT(showNormal()));
-  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 
-          this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
-  connect(m_scene, SIGNAL(rosterChanged(QStringList)), 
-          this, SLOT(updateRosterList(QStringList)));
-  connect(this, SIGNAL(triggerHello()),
-          this, SLOT(sendHello()));
-  connect(this, SIGNAL(triggerJoin()),
-          this, SLOT(sendJoin()));
-  connect(this, SIGNAL(triggerLeave()),
-          this, SLOT(sendLeave()));
-  connect(this, SIGNAL(triggerReplot()),
-          this, SLOT(replot()));
-  connect(this, SIGNAL(triggerEnableTreeDisplay()),
-          this, SLOT(enableTreeDisplay()));
-  connect(this, SIGNAL(triggerReap()),
-          this, SLOT(reap()));
-  
-
-
-  initializeSync();
-}
-
-
-ChatDialog::~ChatDialog()
-{
-  if(m_sock != NULL)
-    {
-      sendLeave();
-      delete m_sock;
-      m_sock = NULL;
-    }
-}
-
-void
-ChatDialog::initializeSetting()
-{
-  m_user.setNick(QString::fromStdString(m_nick));
-  m_user.setChatroom(QString::fromStdString(m_chatroomPrefix.get(-1).toEscapedString()));
-  m_user.setOriginPrefix(QString::fromStdString(m_localPrefix.toUri()));
-  m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
-  m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
-}
-
-void
-ChatDialog::updateLabels()
-{
-  QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
-  ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
-  ui->infoLabel->setText(settingDisp);
-  QString prefixDisp;
-  if (m_user.getPrefix().startsWith("/private/local"))
-  {
-    prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
-    ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
-  }
-  else
-  {
-    prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
-    ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
-  }
-  ui->prefixLabel->setText(prefixDisp);
-}
-
-void
-ChatDialog::initializeSync()
-{
-  
-  m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
-                                m_syncValidator,
-                                m_face,
-                                bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
-                                bind(&ChatDialog::processRemoveWrapper, this, _1));
-  
-  usleep(100000);
-
-  m_scheduler.scheduleEvent(time::milliseconds(600), bind(&ChatDialog::sendJoinWrapper, this));
-
-  if(static_cast<bool>(m_replotEventId))
-    m_scheduler.cancelEvent(m_replotEventId);
-  m_replotEventId = m_scheduler.schedulePeriodicEvent(time::seconds(0), time::milliseconds(FRESHNESS * 1000),
-                                                      bind(&ChatDialog::replotWrapper, this));
-  disableTreeDisplay();
-  m_scheduler.scheduleEvent(time::milliseconds(2200), bind(&ChatDialog::enableTreeDisplayWrapper, this));
-}
-
-void
-ChatDialog::sendInterest(const ndn::Interest& interest,
-                         const OnDataValidated& onValidated,
-                         const OnDataValidationFailed& onValidationFailed,
-                         const OnEventualTimeout& timeoutNotify,
-                         int retry /* = 1 */)
-{
-  m_face->expressInterest(interest, 
-                          bind(&ChatDialog::onTargetData, 
-                               this, _1, _2, onValidated, onValidationFailed),
-                          bind(&ChatDialog::onTargetTimeout,
-                               this, _1, retry, 
-                               onValidated, onValidationFailed, timeoutNotify));
-}
-
-void
-ChatDialog::sendInvitation(shared_ptr<ContactItem> contact, bool isIntroducer)
-{
-#ifdef WITH_SECURITY
-  m_invitationValidator->addTrustAnchor(contact->getSelfEndorseCertificate());
-#endif
-
-  Invitation invitation(contact->getNameSpace(),
-                               m_chatroomPrefix.get(-1),
-                               m_localPrefix);
-  ndn::Interest interest(invitation.getUnsignedInterestName());
-
-  m_keyChain->signByIdentity(interest, m_defaultIdentity);
-
-  OnDataValidated onValidated = bind(&ChatDialog::onInviteReplyValidated,
-                                     this, _1, contact->getNameSpace(), isIntroducer);
-
-  OnDataValidationFailed onValidationFailed = bind(&ChatDialog::onInviteReplyValidationFailed,
-                                                   this, _1, contact->getNameSpace());
-
-  OnEventualTimeout timeoutNotify = bind(&ChatDialog::onInviteReplyTimeout,
-                                         this, contact->getNameSpace());
-                                                 
-  sendInterest(interest, onValidated, onValidationFailed, timeoutNotify);
-}
-
-void 
-ChatDialog::onInviteReplyValidated(const shared_ptr<const Data>& data, 
-                                   const Name& identity, 
-                                   bool isIntroducer)
-{
-  string content(reinterpret_cast<const char*>(data->getContent().value()), data->getContent().value_size());
-  if(content == string("nack"))
-    invitationRejected(identity);
-  else
-    invitationAccepted(identity, data, content, isIntroducer);
-}
-
-void
-ChatDialog::onInviteReplyValidationFailed(const shared_ptr<const Data>& data,
-                                          const Name& identity)
-{
-  QString msg = QString::fromUtf8("Reply from ") + QString::fromStdString(identity.toUri()) + " cannot be verified!";
-  emit inivationRejection(msg);
-}
-
-
-void
-ChatDialog::onInviteReplyTimeout(const Name& identity)
-{
-  QString msg = QString::fromUtf8("Your invitation to ") + QString::fromStdString(identity.toUri()) + " times out!";
-  emit inivationRejection(msg);
-}
-
-void
-ChatDialog::invitationRejected(const Name& identity)
-{
-  QString msg = QString::fromStdString(identity.toUri()) + " Rejected your invitation!";
-  emit inivationRejection(msg);
-}
-
-void
-ChatDialog::invitationAccepted(const Name& identity, 
-                               shared_ptr<const Data> data, 
-                               const string& inviteePrefix, 
-                               bool isIntroducer)
-{
-  _LOG_DEBUG(" " << identity.toUri() << " Accepted your invitation!");
-
-#ifdef WITH_SECURITY
-  SignatureSha256WithRsa sig(data->getSignature());
-  const Name & keyLocatorName = sig.getKeyLocator().getName();
-  shared_ptr<IdentityCertificate> dskCertificate = m_invitationValidator->getValidatedDskCertificate(keyLocatorName);
-  m_syncPolicy->addSyncDataRule(inviteePrefix, *dskCertificate, isIntroducer);
-  publishIntroCert(*dskCertificate, isIntroducer);
-#endif
-}
-
-void
-ChatDialog::publishIntroCert(const IdentityCertificate& dskCertificate, bool isIntroducer)
-{
-#ifdef WITH_SECURITY
-  SyncIntroCertificate syncIntroCertificate(m_chatroomPrefix,
-                                            dskCertificate.getPublicKeyName(),
-                                            m_keyChain->getDefaultKeyNameForIdentity(m_defaultIdentity),
-                                            dskCertificate.getNotBefore(),
-                                            dskCertificate.getNotAfter(),
-                                            dskCertificate.getPublicKeyInfo(),
-                                            (isIntroducer ? SyncIntroCertificate::INTRODUCER : SyncIntroCertificate::PRODUCER));
-  ndn::Name certName = m_keyChain->getDefaultCertificateNameForIdentity(m_defaultIdentity);
-  _LOG_DEBUG("Publish Intro Certificate: " << syncIntroCertificate.getName());
-  m_keyChain->sign(syncIntroCertificate, certName);
-  m_face->put(syncIntroCertificate);
-#endif
-}
-
-void
-ChatDialog::addChatDataRule(const Name& prefix, 
-                            const IdentityCertificate& identityCertificate,
-                            bool isIntroducer)
-{ 
-#ifdef WITH_SECURITY
-  m_syncValidator->addSyncDataRule(prefix, identityCertificate, isIntroducer); 
-#endif
-}
-
-void
-ChatDialog::addTrustAnchor(const EndorseCertificate& cert)
-{
-#ifdef WITH_SECURITY
-  m_syncValidator->addTrustAnchor(cert);
-#endif
-}
-
-
-void
-ChatDialog::returnPressed()
-{
-  QString text = ui->lineEdit->text();
-  if (text.isEmpty())
-    return;
-
-  ui->lineEdit->clear();
-
-  if (text.startsWith("boruoboluomi"))
-  {
-    summonReaper ();
-    // reapButton->show();
-    fitView();
-    return;
-  }
-
-  if (text.startsWith("minimanihong"))
-  {
-    // reapButton->hide();
-    fitView();
-    return;
-  }
-
-  SyncDemo::ChatMessage msg;
-  formChatMessage(text, msg);
-
-  appendMessage(msg);
-
-  sendMsg(msg);
-
-  fitView();
-}
-
-void 
-ChatDialog::treeButtonPressed()
-{
-  if (ui->treeViewer->isVisible())
-  {
-    ui->treeViewer->hide();
-    ui->treeButton->setText("Show ChronoSync Tree");
-  }
-  else
-  {
-    ui->treeViewer->show();
-    ui->treeButton->setText("Hide ChronoSync Tree");
-  }
-
-  fitView();
-}
-
-void ChatDialog::disableTreeDisplay()
-{
-  ui->treeButton->setEnabled(false);
-  ui->treeViewer->hide();
-  fitView();
-}
-
-void ChatDialog::enableTreeDisplay()
-{
-  ui->treeButton->setEnabled(true);
-  // treeViewer->show();
-  // fitView();
-}
-
-void
-ChatDialog::enableTreeDisplayWrapper()
-{ emit triggerEnableTreeDisplay(); }
-
-void
-ChatDialog::processTreeUpdateWrapper(const vector<Sync::MissingDataInfo>& v, Sync::SyncSocket *sock)
-{
-  emit treeUpdated(v);
-  _LOG_DEBUG("<<< Tree update signal emitted");
-}
-
-void
-ChatDialog::processRemoveWrapper(string prefix)
-{
-  _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
-}
-
-void
-ChatDialog::processTreeUpdate(const vector<Sync::MissingDataInfo>& v)
-{
-  _LOG_DEBUG("<<< processing Tree Update");
-
-  if (v.empty())
-  {
-    return;
-  }
-
-  // reflect the changes on digest tree
-  {
-    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-    m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
-  }
-
-  int n = v.size();
-  int totalMissingPackets = 0;
-  for (int i = 0; i < n; i++)
-  {
-    totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
-  }
-
-  for (int i = 0; i < n; i++)
-  {
-    if (totalMissingPackets < 4)
-    {
-      for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
-      {
-        m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
-        _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
-      }
-    }
-    else
-    {
-        m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
-    }
-  }
-
-  // adjust the view
-  fitView();
-
-}
-
-void
-ChatDialog::processDataWrapper(const shared_ptr<const Data>& data)
-{
-  emit dataReceived(data, true, false);
-  _LOG_DEBUG("<<< " << data->getName() << " fetched");
-}
-
-void
-ChatDialog::processDataNoShowWrapper(const shared_ptr<const Data>& data)
-{ emit dataReceived(data, false, false); }
-
-void
-ChatDialog::processData(shared_ptr<const Data> data, bool show, bool isHistory)
-{
-  SyncDemo::ChatMessage msg;
-  bool corrupted = false;
-  if (!msg.ParseFromArray(data->getContent().value(), data->getContent().value_size()))
-  {
-    _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << data->getName() << ". what is happening?");
-    // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
-    msg.set_from("inconnu");
-    msg.set_type(SyncDemo::ChatMessage::OTHER);
-    corrupted = true;
-  }
-
-  // display msg received from network
-  // we have to do so; this function is called by ccnd thread
-  // so if we call appendMsg directly
-  // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
-  // the "cannonical" way to is use signal-slot
-  if (show && !corrupted)
-  {
-    appendMessage(msg, isHistory);
-  }
-
-  if (!isHistory)
-  {
-    // update the tree view
-    std::string stdStrName = data->getName().toUri();
-    std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
-    std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
-    _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
-    if (msg.type() == SyncDemo::ChatMessage::LEAVE)
-    {
-      processRemove(prefix.c_str());
-    }
-    else
-    {
-      boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-      m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
-    }
-  }
-  fitView();
-}
-
-void
-ChatDialog::processRemove(QString prefix)
-{
-  _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
-
-  bool removed = m_scene->removeNode(prefix);
-  if (removed)
-  {
-    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-    m_scene->plot(m_sock->getRootDigest().c_str());
-  }
-}
-
-void
-ChatDialog::sendJoin()
-{
-  m_joined = true;
-  SyncDemo::ChatMessage msg;
-  formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
-  sendMsg(msg);
-  boost::random::random_device rng;
-  boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
-  m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
-  m_scheduler.scheduleEvent(time::milliseconds(m_randomizedInterval), bind(&ChatDialog::sendHelloWrapper, this));
-}
-
-void
-ChatDialog::sendJoinWrapper()
-{ emit triggerJoin(); }
-
-void
-ChatDialog::sendHello()
-{
-  int64_t now = time::now();
-  int elapsed = (now - m_lastMsgTime) / 1000000000;
-  if (elapsed >= m_randomizedInterval / 1000)
-  {
-    SyncDemo::ChatMessage msg;
-    formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
-    sendMsg(msg);
-    boost::random::random_device rng;
-    boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
-    m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
-    m_scheduler.scheduleEvent(time::milliseconds(m_randomizedInterval), bind(&ChatDialog::sendHelloWrapper, this));
-  }
-  else
-  {
-    m_scheduler.scheduleEvent(time::milliseconds(m_randomizedInterval - elapsed * 1000), 
-                              bind(&ChatDialog::sendHelloWrapper, this));
-  }
-}
-
-void
-ChatDialog::sendHelloWrapper()
-{ emit triggerHello(); }
-
-void
-ChatDialog::sendLeave()
-{
-  SyncDemo::ChatMessage msg;
-  formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
-  sendMsg(msg);
-  usleep(500000);
-  m_sock->remove(m_user.getPrefix().toStdString());
-  usleep(5000);
-  m_joined = false;
-  _LOG_DEBUG("Sync REMOVE signal sent");
-}
-
-void
-ChatDialog::sendLeaveWrapper()
-{ emit triggerLeave(); }
-
-void
-ChatDialog::replot()
-{
-  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-  m_scene->plot(m_sock->getRootDigest().c_str());
-  fitView();
-}
-
-void
-ChatDialog::replotWrapper()
-{ emit triggerReplot(); }
-
-void
-ChatDialog::summonReaper()
-{
-  Sync::SyncLogic &logic = m_sock->getLogic ();
-  map<string, bool> branches = logic.getBranchPrefixes();
-  QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
-
-  m_zombieList.clear();
-
-  QMapIterator<QString, DisplayUserPtr> it(roster);
-  map<string, bool>::iterator mapIt;
-  while(it.hasNext())
-  {
-    it.next();
-    DisplayUserPtr p = it.value();
-    if (p != DisplayUserNullPtr)
-    {
-      mapIt = branches.find(p->getPrefix().toStdString());
-      if (mapIt != branches.end())
-      {
-        mapIt->second = true;
-      }
-    }
-  }
-
-  for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
-  {
-    // this is zombie. all active users should have been marked true
-    if (! mapIt->second)
-    {
-      m_zombieList.append(mapIt->first.c_str());
-    }
-  }
-
-  m_zombieIndex = 0;
-
-  // start reaping
-  reap();
-}
-
-void
-ChatDialog::reap()
-{
-  if (m_zombieIndex < m_zombieList.size())
-  {
-    string prefix = m_zombieList.at(m_zombieIndex).toStdString();
-    m_sock->remove(prefix);
-    _LOG_DEBUG("Reaped: prefix = " << prefix);
-    m_zombieIndex++;
-    // reap again in 10 seconds
-    m_scheduler.scheduleEvent(time::milliseconds(10000), 
-                              bind(&ChatDialog::reapWrapper, this));
-  }
-}
-
-void
-ChatDialog::reapWrapper()
-{ emit triggerReap(); }
-
-void
-ChatDialog::updateRosterList(QStringList staleUserList)
-{
-  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-  QStringList rosterList = m_scene->getRosterList();
-  m_rosterModel->setStringList(rosterList);
-  QString user;
-  QStringListIterator it(staleUserList);
-  while(it.hasNext())
-  {
-    std::string nick = it.next().toStdString();
-    if (nick.empty())
-      continue;
-
-    SyncDemo::ChatMessage msg;
-    formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
-    msg.set_from(nick);
-    appendMessage(msg);
-  }
-}
-
-void
-ChatDialog::settingUpdated(QString nick, QString chatroom, QString originPrefix)
-{
-  _LOG_DEBUG("called");
-  QString randString = getRandomString();
-  bool needWrite = false;
-  bool needFresh = false;
-
-  QString oldPrefix = m_user.getPrefix();
-  if (!originPrefix.isEmpty() && originPrefix != m_user.getOriginPrefix()) {
-    m_user.setOriginPrefix(originPrefix);
-
-    m_localPrefix = ndn::Name(originPrefix.toStdString());
-    m_localChatPrefix = m_localPrefix;
-    m_localChatPrefix.append("%F0.").append(m_defaultIdentity);
-    m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1)).append(randString.toStdString());
-    m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
-    m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
-    needWrite = true;
-    needFresh = true;
-  }
-
-  if (needWrite) {
-    updateLabels();
-  }
-
-  if (needFresh && m_sock != NULL)
-  {
-
-    {
-      boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-      m_scene->clearAll();
-      m_scene->plot("Empty");
-    }
-
-    ui->textEdit->clear();
-
-    // keep the new prefix
-    QString newPrefix = m_user.getPrefix();
-    // send leave for the old
-    m_user.setPrefix(oldPrefix);
-    // there is no point to send leave if we haven't joined yet
-    if (m_joined)
-    {
-      sendLeave();
-    }
-    // resume new prefix
-    m_user.setPrefix(newPrefix);
-    delete m_sock;
-    m_sock = NULL;
-
-    try
-    {
-      usleep(100000);
-      m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
-                                    m_syncValidator,
-                                    m_face,
-                                    bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
-                                    bind(&ChatDialog::processRemoveWrapper, this, _1));
-      usleep(100000);
-      m_scheduler.scheduleEvent(time::milliseconds(600), bind(&ChatDialog::sendJoinWrapper, this));
-      if(static_cast<bool>(m_replotEventId))
-        m_scheduler.cancelEvent(m_replotEventId);
-      m_replotEventId = m_scheduler.schedulePeriodicEvent(time::seconds(0), time::milliseconds(FRESHNESS * 1000),
-                                                          bind(&ChatDialog::replotWrapper, this));
-      disableTreeDisplay();
-      m_scheduler.scheduleEvent(time::milliseconds(2200), bind(&ChatDialog::enableTreeDisplayWrapper, this));
-    }catch(Face::Error& e){
-      emit noNdnConnection(QString::fromStdString("Cannot conect to ndnd!\n Have you started your ndnd?"));
-    }
-  }
-  else if (needFresh && m_sock == NULL)
-  {
-    initializeSync();
-  }
-  else if (m_sock == NULL)
-  {
-    initializeSync();
-  }
-  else
-  {
-// #ifdef __DEBUG
-//     std::cout << "Just changing nicks, we're good. " << std::endl;
-// #endif
-  }
-
-  fitView();
-}
-
-void
-ChatDialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
-{
-  switch (reason)
-  {
-  case QSystemTrayIcon::Trigger:
-  case QSystemTrayIcon::DoubleClick:
-    break;
-  case QSystemTrayIcon::MiddleClick:
-    // showMessage();
-    break;
-  default:;
-  }
-}
-
-
-void
-ChatDialog::messageClicked()
-{
-  this->showMaximized();
-}
-
-
-void
-ChatDialog::createActions()
-{
-  minimizeAction = new QAction(tr("Mi&nimize"), this);
-  connect(minimizeAction, SIGNAL(triggered()), this, SLOT(hide()));
-
-  maximizeAction = new QAction(tr("Ma&ximize"), this);
-  connect(maximizeAction, SIGNAL(triggered()), this, SLOT(showMaximized()));
-
-  restoreAction = new QAction(tr("&Restore"), this);
-  connect(restoreAction, SIGNAL(triggered()), this, SLOT(showNormal()));
-
-  // settingsAction = new QAction(tr("Settings"), this);
-  // connect (settingsAction, SIGNAL(triggered()), this, SLOT(buttonPressed()));
-
-  // settingsAction->setMenuRole (QAction::PreferencesRole);
-
-  updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
-  connect (updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(updateLocalPrefix()));
-
-  quitAction = new QAction(tr("Quit"), this);
-  connect(quitAction, SIGNAL(triggered()), this, SLOT(quit()));
-}
-
-void
-ChatDialog::createTrayIcon()
-{
-  trayIconMenu = new QMenu(this);
-  trayIconMenu->addAction(minimizeAction);
-  trayIconMenu->addAction(maximizeAction);
-  trayIconMenu->addAction(restoreAction);
-  // trayIconMenu->addSeparator();
-  // trayIconMenu->addAction(settingsAction);
-  trayIconMenu->addSeparator();
-  trayIconMenu->addAction(updateLocalPrefixAction);
-  trayIconMenu->addSeparator();
-  trayIconMenu->addAction(quitAction);
-
-  trayIcon = new QSystemTrayIcon(this);
-  trayIcon->setContextMenu(trayIconMenu);
-
-  QIcon icon(":/images/icon_small.png");
-  trayIcon->setIcon(icon);
-  setWindowIcon(icon);
-  trayIcon->setToolTip("ChronoChat System Tray Icon");
-  trayIcon->setVisible(true);
-}
-
-
-void
-ChatDialog::resizeEvent(QResizeEvent *e)
-{
-  fitView();
-}
-
-void
-ChatDialog::showEvent(QShowEvent *e)
-{
-  fitView();
-}
-
-void
-ChatDialog::fitView()
-{
-  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-  QRectF rect = m_scene->itemsBoundingRect();
-  m_scene->setSceneRect(rect);
-  ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
-}
-
-void
-ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
-  msg.set_from(m_user.getNick().toStdString());
-  msg.set_to(m_user.getChatroom().toStdString());
-  msg.set_data(text.toUtf8().constData());
-  int32_t seconds = static_cast<int32_t>(time::now()/1000000000);
-  msg.set_timestamp(seconds);
-  msg.set_type(SyncDemo::ChatMessage::CHAT);
-}
-
-void
-ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
-{
-  msg.set_from(m_user.getNick().toStdString());
-  msg.set_to(m_user.getChatroom().toStdString());
-  int32_t seconds = static_cast<int32_t>(time::now()/1000000000);
-  msg.set_timestamp(seconds);
-  msg.set_type(type);
-}
-
-void
-ChatDialog::updateLocalPrefix()
-{
-  ndn::Name interestName("/local/ndn/prefix");
-  ndn::Interest interest(interestName);
-  interest.setInterestLifetime(1000);
-
-  m_face->expressInterest(interest, 
-                          bind(&ChatDialog::onLocalPrefix, this, _1, _2), 
-                          bind(&ChatDialog::onLocalPrefixTimeout, this, _1));  
-}
-
-
-void
-ChatDialog::onLocalPrefix(const ndn::Interest& interest, 
-                          ndn::Data& data)
-{
-  string dataString(reinterpret_cast<const char*>(data.getContent().value()), data.getContent().value_size());
-  QString originPrefix = QString::fromStdString (dataString).trimmed ();
-  string trimmedString = originPrefix.toStdString();
-  m_newLocalPrefix = Name(trimmedString);
-
-  _LOG_DEBUG("now the prefix is " << m_newLocalPrefix.toUri());
-  _LOG_DEBUG("in use prefix is " << m_user.getOriginPrefix().toStdString());
-    
-  if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
-    emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
-}
-
-void
-ChatDialog::onLocalPrefixTimeout(const ndn::Interest& interest)
-{
-  m_newLocalPrefix = m_localPrefix;
-
-  _LOG_DEBUG("now the prefix is " << m_newLocalPrefix.toUri());
-  _LOG_DEBUG("in use prefix is " << m_user.getOriginPrefix().toStdString());
-  QString originPrefix = QString::fromStdString(m_newLocalPrefix.toUri());
-    
-  if (originPrefix != "" && m_user.getOriginPrefix () != originPrefix)
-    emit settingUpdated(m_user.getNick (), m_user.getChatroom (), originPrefix);
-}
-
-static std::string chars2("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
-
-QString
-ChatDialog::getRandomString()
-{
-  std::string randStr;
-  boost::random::random_device rng;
-  boost::random::uniform_int_distribution<> index_dist(0, chars2.size() - 1);
-  for (int i = 0; i < 10; i ++)
-  {
-    randStr += chars2[index_dist(rng)];
-  }
-  return randStr.c_str();
-}
-
-void
-ChatDialog::changeEvent(QEvent *e)
-{
-  switch(e->type())
-  {
-  case QEvent::ActivationChange:
-    if (isActiveWindow())
-    {
-      trayIcon->setIcon(QIcon(":/images/icon_small.png"));
-    }
-    break;
-  default:
-    break;
-  }
-}
-
-void
-ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
-{
-  boost::recursive_mutex::scoped_lock lock(m_msgMutex);
-
-  if (msg.type() == SyncDemo::ChatMessage::CHAT)
-  {
-
-    if (!msg.has_data())
-    {
-      return;
-    }
-
-    if (msg.from().empty() || msg.data().empty())
-    {
-      return;
-    }
-
-    if (!msg.has_timestamp())
-    {
-      return;
-    }
-
-    // if (m_history.size() == MAX_HISTORY_ENTRY)
-    // {
-    //   m_history.dequeue();
-    // }
-
-    // m_history.enqueue(msg);
-
-    QTextCharFormat nickFormat;
-    nickFormat.setForeground(Qt::darkGreen);
-    nickFormat.setFontWeight(QFont::Bold);
-    nickFormat.setFontUnderline(true);
-    nickFormat.setUnderlineColor(Qt::gray);
-
-    QTextCursor cursor(ui->textEdit->textCursor());
-    cursor.movePosition(QTextCursor::End);
-    QTextTableFormat tableFormat;
-    tableFormat.setBorder(0);
-    QTextTable *table = cursor.insertTable(1, 2, tableFormat);
-    QString from = QString("%1 ").arg(msg.from().c_str());
-    QTextTableCell fromCell = table->cellAt(0, 0);
-    fromCell.setFormat(nickFormat);
-    fromCell.firstCursorPosition().insertText(from);
-
-    time_t timestamp = msg.timestamp();
-    printTimeInCell(table, timestamp);
-
-    QTextCursor nextCursor(ui->textEdit->textCursor());
-    nextCursor.movePosition(QTextCursor::End);
-    table = nextCursor.insertTable(1, 1, tableFormat);
-    table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
-    if (!isHistory)
-    {
-      showMessage(from, QString::fromUtf8(msg.data().c_str()));
-    }
-  }
-
-  if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
-  {
-    QTextCharFormat nickFormat;
-    nickFormat.setForeground(Qt::gray);
-    nickFormat.setFontWeight(QFont::Bold);
-    nickFormat.setFontUnderline(true);
-    nickFormat.setUnderlineColor(Qt::gray);
-
-    QTextCursor cursor(ui->textEdit->textCursor());
-    cursor.movePosition(QTextCursor::End);
-    QTextTableFormat tableFormat;
-    tableFormat.setBorder(0);
-    QTextTable *table = cursor.insertTable(1, 2, tableFormat);
-    QString action;
-    if (msg.type() == SyncDemo::ChatMessage::JOIN)
-    {
-      action = "enters room";
-    }
-    else
-    {
-      action = "leaves room";
-    }
-
-    QString from = QString("%1 %2  ").arg(msg.from().c_str()).arg(action);
-    QTextTableCell fromCell = table->cellAt(0, 0);
-    fromCell.setFormat(nickFormat);
-    fromCell.firstCursorPosition().insertText(from);
-
-    time_t timestamp = msg.timestamp();
-    printTimeInCell(table, timestamp);
-  }
-
-  QScrollBar *bar = ui->textEdit->verticalScrollBar();
-  bar->setValue(bar->maximum());
-}
-
-QString
-ChatDialog::formatTime(time_t timestamp)
-{
-  struct tm *tm_time = localtime(&timestamp);
-  int hour = tm_time->tm_hour;
-  QString amOrPM;
-  if (hour > 12)
-  {
-    hour -= 12;
-    amOrPM = "PM";
-  }
-  else
-  {
-    amOrPM = "AM";
-    if (hour == 0)
-    {
-      hour = 12;
-    }
-  }
-
-  char textTime[12];
-  sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
-  return QString(textTime);
-}
-
-void
-ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
-{
-  QTextCharFormat timeFormat;
-  timeFormat.setForeground(Qt::gray);
-  timeFormat.setFontUnderline(true);
-  timeFormat.setUnderlineColor(Qt::gray);
-  QTextTableCell timeCell = table->cellAt(0, 1);
-  timeCell.setFormat(timeFormat);
-  timeCell.firstCursorPosition().insertText(formatTime(timestamp));
-}
-
-void
-ChatDialog::showMessage(QString from, QString data)
-{
-  if (!isActiveWindow())
-  {
-    trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
-    trayIcon->setIcon(QIcon(":/images/note.png"));
-  }
-}
-
-void
-ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
-{
-  // send msg
-  size_t size = msg.ByteSize();
-  char *buf = new char[size];
-  msg.SerializeToArray(buf, size);
-  
-  if (!msg.IsInitialized())
-  {
-    _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
-    abort();
-  }
-  m_sock->publishData(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
-
-  delete[] buf;
-
-  m_lastMsgTime = time::now();
-
-  uint64_t nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
-  Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
-  std::vector<Sync::MissingDataInfo> v;
-  v.push_back(mdi);
-  {
-    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-    m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
-    m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
-  }
-}
-
-void
-ChatDialog::openInviteListDialog()
-{
-  m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
-  m_inviteListDialog->show();
-}
-
-void
-ChatDialog::sendInvitationWrapper(QString invitee, bool isIntroducer)
-{
-  Name inviteeNamespace(invitee.toStdString());
-  shared_ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
-  sendInvitation(inviteeItem, isIntroducer);
-}
-
-void
-ChatDialog::closeEvent(QCloseEvent *e)
-{
-  if (trayIcon->isVisible())
-  {
-    QMessageBox::information(this, tr("Chronos"),
-                             tr("The program will keep running in the "
-                                "system tray. To terminate the program"
-                                "choose <b>Quit</b> in the context memu"
-                                "of the system tray entry."));
-    hide();
-    e->ignore();
-  }
-}
-
-void
-ChatDialog::quit()
-{
-  hide();
-  emit closeChatDialog(m_chatroomPrefix);
-}
-
-
-
-
-#if WAF
-#include "chatdialog.moc"
-#include "chatdialog.cpp.moc"
-#endif
diff --git a/src/chatdialog.h b/src/chatdialog.h
deleted file mode 100644
index 5b7eea2..0000000
--- a/src/chatdialog.h
+++ /dev/null
@@ -1,392 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
- *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
- *         Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef CHATDIALOG_H
-#define CHATDIALOG_H
-
-#include <QDialog>
-#include <QTextTable>
-#include <QStringListModel>
-#include <QSystemTrayIcon>
-#include <QMenu>
-
-#include "invitelistdialog.h"
-
-#ifndef Q_MOC_RUN
-#include "contact-item.h"
-#include "chatbuf.pb.h"
-#include "digesttreescene.h"
-#include <sync-socket.h>
-#include <sync-seq-no.h>
-#include <ndn-cpp-dev/security/key-chain.hpp>
-#ifdef WITH_SECURITY
-#include "validator-invitation.h"
-#include <validator-sync.h>
-#else
-#include <ndn-cpp-dev/security/validator-null.hpp>
-#endif
-
-#include <boost/thread/locks.hpp>
-#include <boost/thread/recursive_mutex.hpp>
-#include <boost/thread/thread.hpp>
-#endif
-
-typedef ndn::function<void()> OnEventualTimeout;
-
-#define MAX_HISTORY_ENTRY   20
-
-namespace Ui {
-class ChatDialog;
-}
-
-class ChatDialog : public QDialog
-{
-  Q_OBJECT
-
-public:
-  explicit ChatDialog(ndn::shared_ptr<chronos::ContactManager> contactManager,
-                      ndn::shared_ptr<ndn::Face> face,
-                      const ndn::Name& chatroomPrefix,
-                      const ndn::Name& localPrefix,
-                      const ndn::Name& defaultIdentity,
-                      const std::string& nick,
-                      QWidget *parent = 0);
-
-  ~ChatDialog();
-
-  const ndn::Name&
-  getChatroomPrefix() const
-  { return m_chatroomPrefix; }
-
-  const ndn::Name&
-  getLocalPrefix() const
-  { return m_localPrefix; }
-
-  void
-  sendInvitation(ndn::shared_ptr<chronos::ContactItem> contact, bool isIntroducer);
-
-  void
-  addChatDataRule(const ndn::Name& prefix, 
-                  const ndn::IdentityCertificate& identityCertificate,
-                  bool isIntroducer);
-
-  void
-  addTrustAnchor(const chronos::EndorseCertificate& selfEndorseCertificate);
-
-  void 
-  appendMessage(const SyncDemo::ChatMessage msg, bool isHistory = false);
-
-  void 
-  processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>&, Sync::SyncSocket *);
-
-  void 
-  processDataWrapper(const ndn::shared_ptr<const ndn::Data>& data);
-
-  void 
-  processDataNoShowWrapper(const ndn::shared_ptr<const ndn::Data>& data);
-
-  void 
-  processRemoveWrapper(std::string);
-
-  void
-  publishIntroCert(const ndn::IdentityCertificate& dskCertificate, bool isIntroducer);
-
-protected:
-  void 
-  closeEvent(QCloseEvent *e);
-
-  void
-  changeEvent(QEvent *e);
-
-private:
-
-  void
-  initializeSetting();
-
-  QString 
-  getRandomString();
-
-  void 
-  updateLabels();
-
-  void
-  initializeSync();
-
-  void
-  onTargetData(const ndn::Interest& interest, 
-               const ndn::Data& data,
-               const ndn::OnDataValidated& onValidated,
-               const ndn::OnDataValidationFailed& onValidationFailed)
-  { m_invitationValidator->validate(data, onValidated, onValidationFailed); }
-
-  void
-  onTargetTimeout(const ndn::Interest& interest, 
-                  int retry,
-                  const ndn::OnDataValidated& onValidated,
-                  const ndn::OnDataValidationFailed& onValidationFailed,
-                  const OnEventualTimeout& timeoutNotify)
-  {
-    if(retry > 0)
-      sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, retry-1);
-    else
-      timeoutNotify();
-  }
-
-  void
-  sendInterest(const ndn::Interest& interest,
-               const ndn::OnDataValidated& onValidated,
-               const ndn::OnDataValidationFailed& onValidationFailed,
-               const OnEventualTimeout& timeoutNotify,
-               int retry = 1);
-  
-  void 
-  onInviteReplyValidated(const ndn::shared_ptr<const ndn::Data>& data, 
-                         const ndn::Name& identity, 
-                         bool isIntroduce);
-
-  void
-  onInviteReplyValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
-                            const ndn::Name& identity);
-
-  void 
-  onInviteReplyTimeout(const ndn::Name& identity);
-
-
-  void
-  invitationRejected(const ndn::Name& identity);
-  
-  void 
-  invitationAccepted(const ndn::Name& identity, 
-                     ndn::shared_ptr<const ndn::Data> data, 
-                     const std::string& inviteePrefix, 
-                     bool isIntroducer);
-
-  void
-  onLocalPrefix(const ndn::Interest& interest, 
-                ndn::Data& data);
-
-  void
-  onLocalPrefixTimeout(const ndn::Interest& interest);
-
-  // void 
-  // fetchHistory(std::string name);
-
-  void 
-  formChatMessage(const QString &text, SyncDemo::ChatMessage &msg);
-
-  void 
-  formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type);
-
-  void 
-  sendMsg(SyncDemo::ChatMessage &msg);
-
-  void 
-  resizeEvent(QResizeEvent *);
-  
-  void 
-  showEvent(QShowEvent *);
-
-  void 
-  fitView();
-
-  void 
-  createActions();
-
-  void
-  createTrayIcon();
-
-  QString 
-  formatTime(time_t);
-
-  void 
-  printTimeInCell(QTextTable *, time_t);
-
-  void 
-  disableTreeDisplay();
-
-signals:  
-  void
-  dataReceived(ndn::shared_ptr<const ndn::Data> data, bool show, bool isHistory);
-
-  void 
-  treeUpdated(const std::vector<Sync::MissingDataInfo>);
-  
-  void 
-  removeReceived(QString prefix);
-
-  void
-  closeChatDialog(const ndn::Name& chatroomPrefix);
-
-  void
-  noNdnConnection(const QString& msg);
-                                     
-  void
-  inivationRejection(const QString& msg);
-
-  void
-  triggerHello();
-             
-  void
-  triggerJoin();
-  
-  void
-  triggerLeave();
-
-  void
-  triggerReplot();
-
-  void
-  triggerEnableTreeDisplay();
-
-  void
-  triggerReap();
-
-public slots:
-  void 
-  processTreeUpdate(const std::vector<Sync::MissingDataInfo>&);
-
-  void 
-  processData(ndn::shared_ptr<const ndn::Data> data, bool show, bool isHistory);
-
-  void 
-  processRemove(QString prefix);
-
-private slots:
-  void
-  returnPressed();
-
-  void 
-  treeButtonPressed();
-
-  void
-  settingUpdated(QString, QString, QString);
-
-  void
-  sendJoinWrapper();
-
-  void 
-  sendJoin();
-
-  void
-  sendHelloWrapper();
-  
-  void
-  sendHello();
-
-  void
-  sendLeave();
-
-  void
-  sendLeaveWrapper();
-
-  void 
-  replot();
-
-  void
-  replotWrapper();
-
-  void 
-  updateRosterList(QStringList);
-
-  void 
-  enableTreeDisplay();
-
-  void
-  enableTreeDisplayWrapper();
-
-  void
-  updateLocalPrefix();
-
-  void 
-  summonReaper();
-
-  void
-  reap();
-
-  void
-  reapWrapper();
-
-  void 
-  iconActivated(QSystemTrayIcon::ActivationReason reason);
-
-  void
-  messageClicked();
-
-  void 
-  showMessage(QString, QString);
-  
-  void
-  openInviteListDialog();
-  
-  void
-  sendInvitationWrapper(QString, bool);
-
-  void
-  quit();
-    
-private:
-  Ui::ChatDialog *ui;
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-  ndn::shared_ptr<ndn::Face> m_face;
-  ndn::shared_ptr<boost::asio::io_service> m_ioService;
-
-  ndn::Name m_chatroomPrefix;
-  ndn::Name m_localPrefix;
-  ndn::Name m_localChatPrefix;
-  ndn::Name m_defaultIdentity;
-  User m_user; 
-  std::string m_nick;
-
-  ndn::Scheduler m_scheduler;
-  ndn::EventId m_replotEventId;
-
-#ifndef WITH_SECURITY
-  ndn::shared_ptr<ndn::Validator> m_invitationValidator;
-  ndn::shared_ptr<ndn::Validator> m_syncValidator; 
-#else
-  ndn::shared_ptr<chronos::ValidatorInvitation> m_invitationValidator;
-  ndn::shared_ptr<Sync::ValidatorSync> m_syncValidator;
-#endif
-  ndn::shared_ptr<ndn::KeyChain> m_keyChain;
-
-  ndn::Name m_newLocalPrefix;
-  bool m_newLocalPrefixReady;
-
-
-  Sync::SyncSocket *m_sock;
-  uint64_t m_session;
-  DigestTreeScene *m_scene;
-  boost::recursive_mutex m_msgMutex;
-  boost::recursive_mutex m_sceneMutex;
-  int64_t m_lastMsgTime;
-  int m_randomizedInterval;
-
-
-  QStringListModel *m_rosterModel;
-  QSystemTrayIcon *trayIcon;
-
-  QAction *minimizeAction;
-  QAction *maximizeAction;
-  QAction *restoreAction;
-  QAction *updateLocalPrefixAction;
-  QAction *quitAction;
-  QMenu *trayIconMenu;
-
-  bool m_joined;
-
-  QList<QString> m_zombieList;
-  int m_zombieIndex;
-
-  InviteListDialog* m_inviteListDialog;
-};
-
-#endif // ChatDIALOG_H
diff --git a/src/config.proto b/src/config.proto
new file mode 100644
index 0000000..59cd8cc
--- /dev/null
+++ b/src/config.proto
@@ -0,0 +1,6 @@
+package ChronoChat;
+
+message Conf {
+  required string identity = 1;
+  optional string nick = 2;
+}
\ No newline at end of file
diff --git a/src/contact-item.cpp b/src/contact-item.cpp
deleted file mode 100644
index 13201ae..0000000
--- a/src/contact-item.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "contact-item.h"
-
-#include "logging.h"
-
-using namespace std;
-using namespace ndn;
-
-INIT_LOGGER("ContactItem");
-
-namespace chronos{
-
-ContactItem::ContactItem(const EndorseCertificate& selfEndorseCertificate,
-                         bool isIntroducer,
-                         const string& alias)
-  : m_selfEndorseCertificate(selfEndorseCertificate)
-  , m_isIntroducer(isIntroducer)
-{
-  Name endorsedkeyName = selfEndorseCertificate.getPublicKeyName();
-
-  m_namespace = endorsedkeyName.getSubName(0, endorsedkeyName.size() - 1);
-
-
-  m_name = selfEndorseCertificate.getProfile().get("name");
-  m_alias = alias.empty() ? m_name : alias;
-  m_institution = selfEndorseCertificate.getProfile().get("institution");
-}
-
-ContactItem::ContactItem(const ContactItem& contactItem)
-  : m_selfEndorseCertificate(contactItem.m_selfEndorseCertificate)
-  , m_namespace(contactItem.m_namespace)
-  , m_alias(contactItem.m_alias)
-  , m_name(contactItem.m_name)
-  , m_institution(contactItem.m_institution)
-  , m_isIntroducer(contactItem.m_isIntroducer)
-  , m_trustScope(contactItem.m_trustScope)
-{}
-
-}
diff --git a/src/contact-item.h b/src/contact-item.h
deleted file mode 100644
index bd3ab8a..0000000
--- a/src/contact-item.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef CHRONOS_CONTACT_ITEM_H
-#define CHRONOS_CONTACT_ITEM_H
-
-#include "endorse-certificate.h"
-#include <ndn-cpp-dev/util/regex.hpp>
-#include <vector>
-
-
-namespace chronos{
-
-class ContactItem
-{
-public:
-  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::const_iterator const_iterator;
-  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::iterator iterator;
-
-  ContactItem(const EndorseCertificate& selfEndorseCertificate,
-              bool isIntroducer = false,
-              const std::string& alias = "");
-
-  ContactItem(const ContactItem& contactItem);
-  
-  virtual
-  ~ContactItem() {}
-
-  const EndorseCertificate&
-  getSelfEndorseCertificate() const
-  { return m_selfEndorseCertificate; }
-
-  const ndn::Name&
-  getNameSpace() const
-  { return m_namespace; }
-
-  const std::string&
-  getAlias() const
-  { return m_alias; }
-
-  const std::string&
-  getName() const
-  { return m_name; }
-
-  const std::string&
-  getInstitution() const
-  { return m_institution; }
-
-  const ndn::Name&
-  getPublicKeyName() const
-  { return m_selfEndorseCertificate.getPublicKeyName(); }
-
-  bool
-  isIntroducer() const
-  { return m_isIntroducer; }
-
-  void
-  setIsIntroducer(bool isIntroducer) 
-  { m_isIntroducer = isIntroducer; }
-
-  void
-  addTrustScope(const ndn::Name& nameSpace)
-  { m_trustScope[nameSpace] = ndn::Regex::fromName(nameSpace); }
-
-  void
-  deleteTrustScope(const ndn::Name& nameSpace)
-  {
-    std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::iterator it = m_trustScope.find(nameSpace);
-    if(it != m_trustScope.end())
-      m_trustScope.erase(it);
-  }
-
-  bool
-  canBeTrustedFor(const ndn::Name& name)
-  {
-    std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::iterator it = m_trustScope.begin();
-
-    for(; it != m_trustScope.end(); it++)
-      if(it->second->match(name))
-        return true;
-    return false;
-  }
-
-  const_iterator
-  trustScopeBegin() const
-  { return m_trustScope.begin(); }
-
-  const_iterator
-  trustScopeEnd() const
-  { return m_trustScope.end(); }
-
-  iterator
-  trustScopeBegin()
-  { return m_trustScope.begin(); }
-
-  iterator
-  trustScopeEnd()
-  { return m_trustScope.end(); }
-
-
-protected:
-  EndorseCertificate m_selfEndorseCertificate;
-
-  ndn::Name m_namespace;
-  std::string m_alias;
-
-  std::string m_name;
-  std::string m_institution;
-
-  bool m_isIntroducer;
-
-  std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> > m_trustScope;
-};
-
-}//chronos
-
-#endif
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
diff --git a/src/contact-manager.h b/src/contact-manager.h
index c61a720..6bcd429 100644
--- a/src/contact-manager.h
+++ b/src/contact-manager.h
@@ -15,17 +15,21 @@
 
 #ifndef Q_MOC_RUN
 #include "contact-storage.h"
-#include "dns-storage.h"
 #include "endorse-certificate.h"
 #include "profile.h"
+#include "endorse-info.pb.h"
+#include "endorse-collection.pb.h"
 #include <ndn-cpp-dev/face.hpp>
 #include <ndn-cpp-dev/security/key-chain.hpp>
 #include <ndn-cpp-dev/security/validator.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/recursive_mutex.hpp>
 #endif
 
 namespace chronos{
 
-typedef ndn::function<void()> TimeoutNotify;
+typedef ndn::function<void(const ndn::Interest&)> TimeoutNotify;
+typedef std::vector<ndn::shared_ptr<Contact> > ContactList;
 
 class ContactManager : public QObject
 {
@@ -37,273 +41,253 @@
 
   ~ContactManager();
 
-  void
-  fetchSelfEndorseCertificate(const ndn::Name& identity);
+  ndn::shared_ptr<Contact>
+  getContact(const ndn::Name& identity)
+  {
+    return m_contactStorage->getContact(identity);
+  }
 
   void
-  fetchKey(const ndn::Name& identity);
+  getContactList(ContactList& contactList)
+  {
+    contactList.clear();
+    contactList.insert(contactList.end(), m_contactList.begin(), m_contactList.end());
+  }
+private:  
+  void
+  initializeSecurity();
 
   void
   fetchCollectEndorse(const ndn::Name& identity);
 
   void
-  fetchIdCertificate(const ndn::Name& certName);
+  fetchEndorseCertificateInternal(const ndn::Name& identity, int certIndex);
 
   void
-  updateProfileData(const ndn::Name& identity);
+  prepareEndorseInfo(const ndn::Name& identity);
+
+  // PROFILE: self-endorse-certificate
+  void 
+  onDnsSelfEndorseCertValidated(const ndn::shared_ptr<const ndn::Data>& selfEndorseCertificate, 
+                                const ndn::Name& identity);
 
   void
-  updateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity);
-
-  inline void
-  getContactItemList(std::vector<ndn::shared_ptr<ContactItem> >& contacts);
-
-  ndn::shared_ptr<ContactStorage>
-  getContactStorage()
-  { return m_contactStorage; }
-
-  inline ndn::shared_ptr<ContactItem>
-  getContact(const ndn::Name& contactNamespace);
-
-  ndn::shared_ptr<DnsStorage>
-  getDnsStorage()
-  { return m_dnsStorage; }
-
-  ndn::Name
-  getDefaultIdentity()
-  { return m_keyChain->getDefaultIdentity(); }
+  onDnsSelfEndorseCertValidationFailed(const ndn::shared_ptr<const ndn::Data>& selfEndorseCertificate, 
+                                       const ndn::Name& identity);
 
   void
-  publishCollectEndorsedDataInDNS(const ndn::Name& identity);
+  onDnsSelfEndorseCertTimeoutNotify(const ndn::Interest& interest,
+                                    const ndn::Name& identity);
+ 
+  // ENDORSED: endorse-collection
+  void
+  onDnsCollectEndorseValidated(const ndn::shared_ptr<const ndn::Data>& data, 
+                               const ndn::Name& identity);
 
   void
-  setDefaultIdentity(const ndn::Name& identity)
-  { m_defaultIdentity = identity; }
+  onDnsCollectEndorseValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, 
+                                      const ndn::Name& identity);
 
   void
-  addContact(const ndn::IdentityCertificate& idCert, const Profile& profile);
+  onDnsCollectEndorseTimeoutNotify(const ndn::Interest& interest,
+                                   const ndn::Name& identity);  
+
+  // PROFILE-CERT: endorse-certificate
+  void
+  onEndorseCertificateInternal(const ndn::Interest& interest,
+                               ndn::Data& data, 
+                               const ndn::Name& identity, 
+                               int certIndex,
+                               std::string hash);
 
   void
-  removeContact(const ndn::Name& contactNameSpace);
+  onEndorseCertificateInternalTimeout(const ndn::Interest& interest,
+                                      const ndn::Name& identity, 
+                                      int certIndex);
+
+  // Collect endorsement
+  void
+  collectEndorsement();
+
+  void
+  onDnsEndorseeValidated(const ndn::shared_ptr<const ndn::Data>& data);
+
+  void
+  onDnsEndorseeValidationFailed(const ndn::shared_ptr<const ndn::Data>& data);
+
+  void
+  onDnsEndorseeTimeoutNotify(const ndn::Interest& interest);
+
+  void
+  decreaseCollectStatus();
+
+  void
+  publishCollectEndorsedDataInDNS();
+
+  // Identity certificate
+  void
+  onIdentityCertValidated(const ndn::shared_ptr<const ndn::Data>& data);
   
-private:  
   void
-  initializeSecurity();
+  onIdentityCertValidationFailed(const ndn::shared_ptr<const ndn::Data>& data);
 
+  void
+  onIdentityCertTimeoutNotify(const ndn::Interest& interest);
+
+  void
+  decreaseIdCertCount();
+
+  // Publish self-endorse certificate
   ndn::shared_ptr<EndorseCertificate>
-  getSignedSelfEndorseCertificate(const ndn::Name& identity, const Profile& profile);
-
-  ndn::shared_ptr<EndorseCertificate> 
-  generateEndorseCertificate(const ndn::Name& identity, const ndn::Name& signerIdentity);
+  getSignedSelfEndorseCertificate(const Profile& profile);
 
   void
   publishSelfEndorseCertificateInDNS(const EndorseCertificate& selfEndorseCertificate);
 
-  void
-  publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate, const ndn::Name& signerIdentity);
+  // Publish endorse certificate
+  ndn::shared_ptr<EndorseCertificate> 
+  generateEndorseCertificate(const ndn::Name& identity);
 
-  inline void
+  void
+  publishEndorseCertificateInDNS(const EndorseCertificate& endorseCertificate);
+
+  // Communication
+  void
   sendInterest(const ndn::Interest& interest,
                const ndn::OnDataValidated& onValidated,
                const ndn::OnDataValidationFailed& onValidationFailed,
                const TimeoutNotify& timeoutNotify,
                int retry = 1);
 
-  inline void
+  void
   onTargetData(const ndn::Interest& interest, 
                const ndn::Data& data,
                const ndn::OnDataValidated& onValidated,
                const ndn::OnDataValidationFailed& onValidationFailed);
 
-  inline void
+  void
   onTargetTimeout(const ndn::Interest& interest, 
                   int retry,
                   const ndn::OnDataValidated& onValidated,
                   const ndn::OnDataValidationFailed& onValidationFailed,
                   const TimeoutNotify& timeoutNotify);
 
-  void 
-  onDnsSelfEndorseCertValidated(const ndn::shared_ptr<const ndn::Data>& selfEndorseCertificate, const ndn::Name& identity);
-
-  inline void
-  onDnsSelfEndorseCertValidationFailed(const ndn::shared_ptr<const ndn::Data>& selfEndorseCertificate, const ndn::Name& identity);
-
-  inline void
-  onDnsSelfEndorseCertTimeoutNotify(const ndn::Name& identity);
- 
-
-  inline void
-  onDnsCollectEndorseValidated(const ndn::shared_ptr<const ndn::Data>& data, const ndn::Name& identity);
-
-  inline void
-  onDnsCollectEndorseValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const ndn::Name& identity);
-
-  inline void
-  onDnsCollectEndorseTimeoutNotify(const ndn::Name& identity);
-
-
+  // DNS listener
   void
-  onKeyValidated(const ndn::shared_ptr<const ndn::Data>& data, const ndn::Name& identity);
-
-  inline void
-  onKeyValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const ndn::Name& identity);
-
-  inline void
-  onKeyTimeoutNotify(const ndn::Name& identity);
-
-
-  inline void
-  onIdCertValidated(const ndn::shared_ptr<const ndn::Data>& data, const ndn::Name& identity);
-
-  inline void
-  onIdCertValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, const ndn::Name& identity);
-
-  inline void
-  onIdCertTimeoutNotify(const ndn::Name& identity);
+  onDnsInterest(const ndn::Name& prefix, const ndn::Interest& interest);
   
+  void
+  onDnsRegisterFailed(const ndn::Name& prefix, const std::string& failInfo);
 
 signals:
   void
-  noNdnConnection(const QString& msg);
-  
-  void 
-  contactFetched(const chronos::EndorseCertificate& endorseCertificate);
+  contactEndorseInfoReady(const chronos::EndorseInfo& endorseInfo);
+
+  void
+  contactInfoFetchFailed(const QString& identity);
+
+  void
+  idCertNameListReady(const QStringList& certNameList);
   
   void
-  contactFetchFailed(const ndn::Name& identity);
+  nameListReady(const QStringList& certNameList);
 
   void
-  contactKeyFetched(const chronos::EndorseCertificate& endorseCertificate);
+  idCertReady(const ndn::IdentityCertificate& idCert);
 
   void
-  contactKeyFetchFailed(const ndn::Name& identity);
+  contactAliasListReady(const QStringList& aliasList);
 
-  void 
-  contactCertificateFetched(const ndn::IdentityCertificate& identityCertificate);
+  void
+  contactIdListReady(const QStringList& idList);
+
+  void
+  contactInfoReady(const QString& identity, 
+                   const QString& name, 
+                   const QString& institute, 
+                   bool isIntro);
+
+  void
+  warning(const QString& msg);
+
+public slots:
+  void
+  onIdentityUpdated(const QString& identity);
+
+  void
+  onFetchContactInfo(const QString& identity);
   
   void
-  contactCertificateFetchFailed(const ndn::Name& identity);
-
-  void 
-  collectEndorseFetched(const ndn::Data& data);
+  onAddFetchedContact(const QString& identity);
 
   void
-  collectEndorseFetchFailed(const ndn::Name& identity);
+  onUpdateProfile();
 
   void
-  warning(QString msg);
+  onRefreshBrowseContact();
 
   void
-  contactRemoved(const ndn::Name& identity);
+  onFetchIdCert(const QString& certName);
 
   void
-  contactAdded(const ndn::Name& identity);                                         
+  onAddFetchedContactIdCert(const QString& identity);
 
-private slots:
+  void
+  onWaitForContactList();
+
+  void
+  onWaitForContactInfo(const QString& identity);
   
-  
+  void
+  onRemoveContact(const QString& identity);
+
+  void
+  onUpdateAlias(const QString& identity, const QString& alias);
+
+  void
+  onUpdateIsIntroducer(const QString& identity, bool isIntro);
+
+  void
+  onUpdateEndorseCertificate(const QString& identity);
+
 private:
 
+  class FetchedInfo {
+  public:
+    ndn::shared_ptr<EndorseCertificate> m_selfEndorseCert;
+    ndn::shared_ptr<EndorseCollection> m_endorseCollection;
+    std::vector<ndn::shared_ptr<EndorseCertificate> > m_endorseCertList;
+    ndn::shared_ptr<EndorseInfo> m_endorseInfo;
+  };
+
+  typedef std::map<ndn::Name, FetchedInfo> BufferedContacts;
+  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::IdentityCertificate> > BufferedIdCerts;
+
+  typedef boost::recursive_mutex RecLock;
+  typedef boost::unique_lock<RecLock> UniqueRecLock;
+
+  // Conf
   ndn::shared_ptr<ContactStorage> m_contactStorage;
-  ndn::shared_ptr<DnsStorage> m_dnsStorage;
   ndn::shared_ptr<ndn::Validator> m_validator;
   ndn::shared_ptr<ndn::Face> m_face;
-  ndn::shared_ptr<ndn::KeyChain> m_keyChain;
-  ndn::Name m_defaultIdentity;
+  ndn::KeyChain m_keyChain;
+  ndn::Name m_identity;
+  ContactList m_contactList;
+
+  // Buffer
+  BufferedContacts m_bufferedContacts;
+  BufferedIdCerts m_bufferedIdCerts;
+
+  // Tmp Dns
+  const ndn::RegisteredPrefixId* m_dnsListenerId;
+
+  RecLock m_collectCountMutex;
+  int m_collectCount;
+
+  RecLock m_idCertCountMutex;
+  int m_idCertCount;
 };
 
-void
-ContactManager::sendInterest(const ndn::Interest& interest,
-                             const ndn::OnDataValidated& onValidated,
-                             const ndn::OnDataValidationFailed& onValidationFailed,
-                             const TimeoutNotify& timeoutNotify,
-                             int retry /* = 1 */)
-{
-  m_face->expressInterest(interest, 
-                          bind(&ContactManager::onTargetData, 
-                               this, _1, _2, onValidated, onValidationFailed),
-                          bind(&ContactManager::onTargetTimeout,
-                               this, _1, retry, onValidated, onValidationFailed, timeoutNotify));
-}
+} // namespace chronos
 
-void
-ContactManager::onTargetData(const ndn::Interest& interest, 
-                             const ndn::Data& data,
-                             const ndn::OnDataValidated& onValidated,
-                             const ndn::OnDataValidationFailed& onValidationFailed)
-{ m_validator->validate(data, onValidated, onValidationFailed); }
-
-void
-ContactManager::onTargetTimeout(const ndn::Interest& interest, 
-                                int retry,
-                                const ndn::OnDataValidated& onValidated,
-                                const ndn::OnDataValidationFailed& onValidationFailed,
-                                const TimeoutNotify& timeoutNotify)
-{
-  if(retry > 0)
-    sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, retry-1);
-  else
-    timeoutNotify();
-}
-
-
-void
-ContactManager::onDnsSelfEndorseCertValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, 
-                                                     const ndn::Name& identity)
-{ emit contactFetchFailed (identity); }
-
-void
-ContactManager::onDnsSelfEndorseCertTimeoutNotify(const ndn::Name& identity)
-{ emit contactFetchFailed(identity); }
-
-void
-ContactManager::onDnsCollectEndorseValidated(const ndn::shared_ptr<const ndn::Data>& data, 
-                                            const ndn::Name& identity)
-{ emit collectEndorseFetched (*data); }
-
-void
-ContactManager::onDnsCollectEndorseValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, 
-                                                const ndn::Name& identity)
-{ emit collectEndorseFetchFailed (identity); }
-
-void
-ContactManager::onDnsCollectEndorseTimeoutNotify(const ndn::Name& identity)
-{ emit collectEndorseFetchFailed (identity); }
-
-void
-ContactManager::onKeyValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, 
-                                  const ndn::Name& identity)
-{ emit contactKeyFetchFailed (identity); }
-
-void
-ContactManager::onKeyTimeoutNotify(const ndn::Name& identity)
-{ emit contactKeyFetchFailed(identity); }
-
-void
-ContactManager::onIdCertValidated(const ndn::shared_ptr<const ndn::Data>& data, 
-                                        const ndn::Name& identity)
-{
-  ndn::IdentityCertificate identityCertificate(*data);
-  emit contactCertificateFetched(identityCertificate);
-}
-
-void
-ContactManager::onIdCertValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, 
-                                            const ndn::Name& identity)
-{ emit contactCertificateFetchFailed (identity); }
-
-void
-ContactManager::onIdCertTimeoutNotify(const ndn::Name& identity)
-{ emit contactCertificateFetchFailed (identity); }
-
-ndn::shared_ptr<ContactItem>
-ContactManager::getContact(const ndn::Name& contactNamespace)
-{ return m_contactStorage->getContact(contactNamespace); }
-
-void
-ContactManager::getContactItemList(std::vector<ndn::shared_ptr<ContactItem> >& contacts)
-{ return m_contactStorage->getAllContacts(contacts); }
-
-}//chronos
-
-#endif
+#endif //CHRONOS_CONTACT_MANAGER_H
diff --git a/src/contact-panel.cpp b/src/contact-panel.cpp
new file mode 100644
index 0000000..2c2c8e9
--- /dev/null
+++ b/src/contact-panel.cpp
@@ -0,0 +1,349 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "contact-panel.h"
+#include "ui_contact-panel.h"
+
+#include <QMenu>
+#include <QItemSelectionModel>
+#include <QModelIndex>
+#include <QtSql/QSqlRecord>
+#include <QtSql/QSqlField>
+#include <QtSql/QSqlError>
+
+#ifndef Q_MOC_RUN
+#include "logging.h"
+#endif
+
+INIT_LOGGER("ContactPanel");
+
+ContactPanel::ContactPanel(QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::ContactPanel)
+  , m_setAliasDialog(new SetAliasDialog)
+  , m_contactListModel(new QStringListModel)
+  , m_trustScopeModel(0)
+  , m_endorseDataModel(0)
+  , m_endorseComboBoxDelegate(new EndorseComboBoxDelegate)
+{
+  ui->setupUi(this);
+  ui->ContactList->setModel(m_contactListModel);
+  m_menuAlias  = new QAction("Set Alias", this);
+  m_menuDelete = new QAction("Delete", this);
+
+  connect(ui->ContactList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+          this, SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &)));
+  connect(ui->ContactList, SIGNAL(customContextMenuRequested(const QPoint&)),
+          this, SLOT(onContextMenuRequested(const QPoint&)));
+  connect(ui->isIntroducer, SIGNAL(stateChanged(int)),
+          this, SLOT(onIsIntroducerChanged(int)));
+  connect(ui->addScope, SIGNAL(clicked()),
+          this, SLOT(onAddScopeClicked()));
+  connect(ui->deleteScope, SIGNAL(clicked()),
+          this, SLOT(onDeleteScopeClicked()));
+  connect(ui->saveButton, SIGNAL(clicked()),
+          this, SLOT(onSaveScopeClicked()));
+  connect(ui->endorseButton, SIGNAL(clicked()),
+          this, SLOT(onEndorseButtonClicked()));
+  connect(m_setAliasDialog, SIGNAL(aliasChanged(const QString&, const QString&)),
+          this, SLOT(onAliasChanged(const QString&, const QString&)));
+}
+
+ContactPanel::~ContactPanel()
+{
+  if(m_contactListModel) delete m_contactListModel;
+  if(m_trustScopeModel)  delete m_trustScopeModel;
+  if(m_endorseDataModel) delete m_endorseDataModel;
+
+  delete m_setAliasDialog;
+  delete m_endorseComboBoxDelegate;
+
+  delete m_menuAlias;
+  delete m_menuDelete;
+
+  delete ui;
+}
+
+//private methods
+void
+ContactPanel::resetPanel()
+{
+  // Clean up General tag.
+  ui->NameData->clear();
+  ui->NameSpaceData->clear();
+  ui->InstitutionData->clear();
+
+  // Clean up TrustScope tag.
+  ui->isIntroducer->setChecked(false);
+  ui->addScope->setEnabled(false);
+  ui->deleteScope->setEnabled(false);
+
+  m_trustScopeModel = new QSqlTableModel;
+  m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
+  m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
+  m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
+
+  ui->trustScopeList->setModel(m_trustScopeModel);
+  ui->trustScopeList->setColumnHidden(0, true);
+  ui->trustScopeList->setColumnHidden(1, true);
+  ui->trustScopeList->show();
+  ui->trustScopeList->setEnabled(false);
+
+  // Clean up Endorse tag.
+  m_endorseDataModel = new QSqlTableModel;
+  m_endorseDataModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Identity"));
+  m_endorseDataModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Type"));
+  m_endorseDataModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Value"));
+  m_endorseDataModel->setHeaderData(3, Qt::Horizontal, QObject::tr("Endorse"));
+
+  ui->endorseList->setModel(m_endorseDataModel);
+  ui->endorseList->setColumnHidden(0, true);
+  ui->endorseList->resizeColumnToContents(1);
+  ui->endorseList->resizeColumnToContents(2);
+  ui->endorseList->setItemDelegateForColumn(3, m_endorseComboBoxDelegate);
+  ui->endorseList->show();
+  ui->endorseList->setEnabled(false);
+
+  // Clean up contact list.
+  m_contactAliasList.clear();
+  m_contactIdList.clear();
+  m_currentSelectedContact.clear();
+  m_contactListModel->setStringList(m_contactAliasList);
+}
+
+// public slots
+void
+ContactPanel::onCloseDBModule()
+{
+  _LOG_DEBUG("close db module");
+  if(m_trustScopeModel)
+    {
+      delete m_trustScopeModel;
+      _LOG_DEBUG("trustScopeModel closed");
+    }
+  if(m_endorseDataModel)
+    {
+      delete m_endorseDataModel;
+      _LOG_DEBUG("endorseDataModel closed");
+    }
+}
+
+void
+ContactPanel::onIdentityUpdated(const QString& identity)
+{
+  resetPanel();
+
+  emit waitForContactList();  // Re-load contact list;
+}
+
+void
+ContactPanel::onContactAliasListReady(const QStringList& aliasList)
+{
+  m_contactAliasList = aliasList;
+  m_contactListModel->setStringList(m_contactAliasList);
+}
+
+void
+ContactPanel::onContactIdListReady(const QStringList& idList)
+{
+  m_currentSelectedContact.clear();
+  m_contactIdList = idList;
+}
+
+void
+ContactPanel::onContactInfoReady(const QString& identity, 
+                                 const QString& name, 
+                                 const QString& institute, 
+                                 bool isIntro)
+{
+  ui->NameData->setText(name);
+  ui->NameSpaceData->setText(identity);
+  ui->InstitutionData->setText(institute);
+
+  QString filter = QString("contact_namespace = '%1'").arg(identity);
+  m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+  m_trustScopeModel->setTable("TrustScope");
+  m_trustScopeModel->setFilter(filter);
+  m_trustScopeModel->select();
+  ui->trustScopeList->setModel(m_trustScopeModel);
+  ui->trustScopeList->setColumnHidden(0, true);
+  ui->trustScopeList->setColumnHidden(1, true);
+  ui->trustScopeList->show();
+
+  if(isIntro)
+    {
+      ui->isIntroducer->setChecked(true);
+      ui->addScope->setEnabled(true);
+      ui->deleteScope->setEnabled(true);     
+      ui->trustScopeList->setEnabled(true);
+    }
+  else
+    {
+      ui->isIntroducer->setChecked(false);
+      ui->addScope->setEnabled(false);
+      ui->deleteScope->setEnabled(false);
+      ui->trustScopeList->setEnabled(false);
+    }
+
+  QString filter2 = QString("profile_identity = '%1'").arg(identity);
+  m_endorseDataModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+  m_endorseDataModel->setTable("ContactProfile");
+  m_endorseDataModel->setFilter(filter2);
+  m_endorseDataModel->select();
+  ui->endorseList->setModel(m_endorseDataModel);
+  ui->endorseList->setColumnHidden(0, true);
+  ui->endorseList->resizeColumnToContents(1);
+  ui->endorseList->resizeColumnToContents(2);
+  ui->endorseList->setItemDelegateForColumn(3, m_endorseComboBoxDelegate);
+  ui->endorseList->show();
+  ui->endorseList->setEnabled(true);
+}
+
+// private slots
+void
+ContactPanel::onSelectionChanged(const QItemSelection &selected,
+                                 const QItemSelection &deselected)
+{
+  QModelIndexList items = selected.indexes();
+  QString alias = m_contactListModel->data(items.first(), Qt::DisplayRole).toString();
+
+  bool contactFound = false;
+  for(int i = 0; i < m_contactAliasList.size(); i++)
+    {
+      if(alias == m_contactAliasList[i])
+        {
+          contactFound = true;
+          m_currentSelectedContact = m_contactIdList[i];
+          break;
+        }
+    }
+
+  if(!contactFound)
+    {
+      emit warning("This should not happen: ContactPanel::updateSelection #1");
+      return;
+    }
+
+  emit waitForContactInfo(m_currentSelectedContact);
+}
+
+void
+ContactPanel::onContextMenuRequested(const QPoint& pos)
+{
+  QMenu menu(ui->ContactList);
+
+  menu.addAction(m_menuAlias);
+  connect(m_menuAlias, SIGNAL(triggered()),
+          this, SLOT(onSetAliasDialogRequested()));
+
+  menu.addAction(m_menuDelete);
+  connect(m_menuDelete, SIGNAL(triggered()),
+          this, SLOT(onContactDeletionRequested()));
+
+  menu.exec(ui->ContactList->mapToGlobal(pos));
+}
+
+void
+ContactPanel::onSetAliasDialogRequested()
+{
+  for(int i = 0; i < m_contactIdList.size(); i++)
+    if(m_contactIdList[i] == m_currentSelectedContact)
+      {
+        m_setAliasDialog->setTargetIdentity(m_currentSelectedContact, m_contactAliasList[i]);
+        m_setAliasDialog->show();
+        return;
+      }
+}
+
+void
+ContactPanel::onContactDeletionRequested()
+{
+  QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
+  QModelIndexList selectedList = selectionModel->selectedIndexes();
+  QModelIndexList::iterator it = selectedList.begin();
+  for(; it != selectedList.end(); it++)
+    {
+      QString alias =  m_contactListModel->data(*it, Qt::DisplayRole).toString();
+      for(int i = 0; i < m_contactAliasList.size(); i++)
+        if(m_contactAliasList[i] == alias)
+          {
+            emit removeContact(m_contactIdList[i]);
+            return;
+          }
+    }
+}
+
+void
+ContactPanel::onIsIntroducerChanged(int state)
+{
+  if(state == Qt::Checked)
+    {
+      ui->addScope->setEnabled(true);
+      ui->deleteScope->setEnabled(true);
+      ui->trustScopeList->setEnabled(true);
+      emit updateIsIntroducer(m_currentSelectedContact, true);
+    }
+  else
+    {
+      ui->addScope->setEnabled(false);
+      ui->deleteScope->setEnabled(false);
+      ui->trustScopeList->setEnabled(false);
+      emit updateIsIntroducer(m_currentSelectedContact, false);
+    }
+}
+
+void
+ContactPanel::onAddScopeClicked()
+{
+  int rowCount = m_trustScopeModel->rowCount();
+  QSqlRecord record;
+  QSqlField identityField("contact_namespace", QVariant::String);
+  record.append(identityField);
+  record.setValue("contact_namespace", m_currentSelectedContact);
+  m_trustScopeModel->insertRow(rowCount);
+  m_trustScopeModel->setRecord(rowCount, record);
+}
+
+void
+ContactPanel::onDeleteScopeClicked()
+{
+  QItemSelectionModel* selectionModel = ui->trustScopeList->selectionModel();
+  QModelIndexList indexList = selectionModel->selectedIndexes();
+
+  int i = indexList.size() - 1;  
+  for(; i >= 0; i--)
+    m_trustScopeModel->removeRow(indexList[i].row());
+    
+  m_trustScopeModel->submitAll();
+}
+
+void
+ContactPanel::onSaveScopeClicked()
+{
+  m_trustScopeModel->submitAll();
+}
+
+void
+ContactPanel::onEndorseButtonClicked()
+{
+  m_endorseDataModel->submitAll();
+  emit updateEndorseCertificate(m_currentSelectedContact);
+}
+
+void
+ContactPanel::onAliasChanged(const QString& identity, const QString& alias)
+{
+  emit updateAlias(identity, alias);
+}
+
+#if WAF
+#include "contact-panel.moc"
+#include "contact-panel.cpp.moc"
+#endif
diff --git a/src/contact-panel.h b/src/contact-panel.h
new file mode 100644
index 0000000..74010fc
--- /dev/null
+++ b/src/contact-panel.h
@@ -0,0 +1,141 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CONTACT_PANEL_H
+#define CONTACT_PANEL_H
+
+#include <QDialog>
+#include <QStringListModel>
+#include <QSqlTableModel>
+
+#include "set-alias-dialog.h"
+#include "endorse-combobox-delegate.h"
+
+#ifndef Q_MOC_RUN
+#endif
+
+
+namespace Ui {
+class ContactPanel;
+}
+
+class ContactPanel : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit 
+  ContactPanel(QWidget *parent = 0);
+
+  virtual
+  ~ContactPanel();
+
+private:
+  void
+  resetPanel();
+
+signals:
+  void
+  waitForContactList();
+
+  void
+  waitForContactInfo(const QString& identity);
+
+  void
+  removeContact(const QString& identity);
+
+  void
+  updateAlias(const QString& identity, const QString& alias);
+
+  void
+  updateIsIntroducer(const QString& identity, bool isIntro);
+  
+  void
+  updateEndorseCertificate(const QString& identity);
+
+  void
+  warning(const QString& msg);
+
+public slots:
+  void
+  onCloseDBModule();
+
+  void
+  onIdentityUpdated(const QString& identity);
+
+  void
+  onContactAliasListReady(const QStringList& aliasList);
+
+  void
+  onContactIdListReady(const QStringList& idList);
+
+  void
+  onContactInfoReady(const QString& identity, 
+                     const QString& name, 
+                     const QString& institute,
+                     bool isIntro);
+  
+private slots:
+  void
+  onSelectionChanged(const QItemSelection &selected,
+                     const QItemSelection &deselected);
+
+  void
+  onContextMenuRequested(const QPoint& pos);
+
+  void
+  onSetAliasDialogRequested();
+
+  void
+  onContactDeletionRequested();
+
+  void
+  onIsIntroducerChanged(int state);
+
+  void
+  onAddScopeClicked();
+
+  void
+  onDeleteScopeClicked();
+
+  void
+  onSaveScopeClicked();
+
+  void
+  onEndorseButtonClicked();
+
+  void 
+  onAliasChanged(const QString& identity, const QString& alias);
+
+private:
+  Ui::ContactPanel* ui;
+
+  // Dialogs.
+  SetAliasDialog* m_setAliasDialog;
+
+  // Models.
+  QStringListModel* m_contactListModel;
+  QSqlTableModel*   m_trustScopeModel;
+  QSqlTableModel*   m_endorseDataModel;
+
+  // Delegates.
+  EndorseComboBoxDelegate* m_endorseComboBoxDelegate;
+
+  // Actions.
+  QAction* m_menuAlias;
+  QAction* m_menuDelete;
+  
+  // Internal data structure.
+  QStringList m_contactAliasList;
+  QStringList m_contactIdList;
+  QString     m_currentSelectedContact;
+};
+
+#endif // CONTACT_PANEL_H
diff --git a/src/contact-panel.ui b/src/contact-panel.ui
new file mode 100644
index 0000000..68c0f6d
--- /dev/null
+++ b/src/contact-panel.ui
@@ -0,0 +1,315 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ContactPanel</class>
+ <widget class="QDialog" name="ContactPanel">
+  <property name="enabled">
+   <bool>true</bool>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>480</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>ChronoChat Contacts</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout_5">
+   <item>
+    <layout class="QHBoxLayout" name="ContactPanelLayout" stretch="3,7">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <property name="sizeConstraint">
+      <enum>QLayout::SetDefaultConstraint</enum>
+     </property>
+     <item>
+      <widget class="QListView" name="ContactList">
+       <property name="contextMenuPolicy">
+        <enum>Qt::CustomContextMenu</enum>
+       </property>
+       <property name="acceptDrops">
+        <bool>false</bool>
+       </property>
+       <property name="editTriggers">
+        <set>QAbstractItemView::NoEditTriggers</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QTabWidget" name="ContactInfo">
+       <property name="currentIndex">
+        <number>0</number>
+       </property>
+       <widget class="QWidget" name="General">
+        <attribute name="title">
+         <string>General</string>
+        </attribute>
+        <layout class="QVBoxLayout" name="verticalLayout_7">
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_6" stretch="2,2,1">
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="2,3,2">
+             <item>
+              <spacer name="horizontalSpacer_2">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="QGraphicsView" name="Avatar"/>
+             </item>
+             <item>
+              <spacer name="horizontalSpacer_3">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+            </layout>
+           </item>
+           <item>
+            <layout class="QVBoxLayout" name="verticalLayout">
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout" stretch="35,100">
+               <property name="spacing">
+                <number>-1</number>
+               </property>
+               <item>
+                <widget class="QLabel" name="NameSpaceLabel">
+                 <property name="font">
+                  <font>
+                   <weight>75</weight>
+                   <bold>true</bold>
+                  </font>
+                 </property>
+                 <property name="text">
+                  <string>Name space</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QLineEdit" name="NameSpaceData">
+                 <property name="font">
+                  <font>
+                   <family>Lucida Grande</family>
+                  </font>
+                 </property>
+                 <property name="readOnly">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="35,100">
+               <item>
+                <widget class="QLabel" name="NameLabel">
+                 <property name="font">
+                  <font>
+                   <weight>75</weight>
+                   <bold>true</bold>
+                  </font>
+                 </property>
+                 <property name="text">
+                  <string>Name</string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QLineEdit" name="NameData">
+                 <property name="font">
+                  <font>
+                   <family>Lucida Grande</family>
+                  </font>
+                 </property>
+                 <property name="readOnly">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+             <item>
+              <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="35,100">
+               <item>
+                <widget class="QLabel" name="InstitutionLabel">
+                 <property name="font">
+                  <font>
+                   <weight>75</weight>
+                   <bold>true</bold>
+                  </font>
+                 </property>
+                 <property name="text">
+                  <string>Institution   </string>
+                 </property>
+                </widget>
+               </item>
+               <item>
+                <widget class="QLineEdit" name="InstitutionData">
+                 <property name="font">
+                  <font>
+                   <family>Lucida Grande</family>
+                  </font>
+                 </property>
+                 <property name="readOnly">
+                  <bool>true</bool>
+                 </property>
+                </widget>
+               </item>
+              </layout>
+             </item>
+            </layout>
+           </item>
+           <item>
+            <spacer name="verticalSpacer">
+             <property name="orientation">
+              <enum>Qt::Vertical</enum>
+             </property>
+             <property name="sizeHint" stdset="0">
+              <size>
+               <width>20</width>
+               <height>40</height>
+              </size>
+             </property>
+            </spacer>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="TrustScope">
+        <attribute name="title">
+         <string>Trust Scope</string>
+        </attribute>
+        <layout class="QVBoxLayout" name="verticalLayout_2">
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_3">
+           <item>
+            <widget class="QCheckBox" name="isIntroducer">
+             <property name="text">
+              <string>Set as introducer</string>
+             </property>
+            </widget>
+           </item>
+           <item>
+            <widget class="QTableView" name="trustScopeList">
+             <attribute name="horizontalHeaderStretchLastSection">
+              <bool>true</bool>
+             </attribute>
+            </widget>
+           </item>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_4">
+             <item>
+              <widget class="QPushButton" name="addScope">
+               <property name="text">
+                <string>Add Scope</string>
+               </property>
+               <property name="autoDefault">
+                <bool>false</bool>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QPushButton" name="deleteScope">
+               <property name="text">
+                <string>Delete Scope</string>
+               </property>
+               <property name="autoDefault">
+                <bool>false</bool>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QPushButton" name="saveButton">
+               <property name="text">
+                <string>Save</string>
+               </property>
+               <property name="autoDefault">
+                <bool>false</bool>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="Endorse">
+        <attribute name="title">
+         <string>Endorse</string>
+        </attribute>
+        <layout class="QVBoxLayout" name="verticalLayout_5">
+         <item>
+          <layout class="QVBoxLayout" name="verticalLayout_4">
+           <item>
+            <widget class="QTableView" name="endorseList">
+             <attribute name="horizontalHeaderStretchLastSection">
+              <bool>true</bool>
+             </attribute>
+            </widget>
+           </item>
+           <item>
+            <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="3,1">
+             <item>
+              <spacer name="horizontalSpacer">
+               <property name="orientation">
+                <enum>Qt::Horizontal</enum>
+               </property>
+               <property name="sizeHint" stdset="0">
+                <size>
+                 <width>40</width>
+                 <height>20</height>
+                </size>
+               </property>
+              </spacer>
+             </item>
+             <item>
+              <widget class="QPushButton" name="endorseButton">
+               <property name="text">
+                <string>Endorse</string>
+               </property>
+               <property name="autoDefault">
+                <bool>false</bool>
+               </property>
+              </widget>
+             </item>
+            </layout>
+           </item>
+          </layout>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/contact-storage.cpp b/src/contact-storage.cpp
index f107f0c..e3c513f 100644
--- a/src/contact-storage.cpp
+++ b/src/contact-storage.cpp
@@ -11,28 +11,32 @@
 #include "contact-storage.h"
 
 #include <boost/filesystem.hpp>
+#include <cryptopp/sha.h>
+#include <cryptopp/filters.h>
+#include <cryptopp/hex.h>
+#include <cryptopp/files.h>
 #include "logging.h"
 
 using namespace std;
 using namespace ndn;
 namespace fs = boost::filesystem;
 
-INIT_LOGGER ("ContactStorage");
+
+INIT_LOGGER ("chronos.ContactStorage");
 
 namespace chronos{
 
 const string INIT_SP_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
   SelfProfile(                                                       \n \
-      profile_identity  BLOB NOT NULL,                               \n \
       profile_type      BLOB NOT NULL,                               \n \
       profile_value     BLOB NOT NULL,                               \n \
                                                                      \
-      PRIMARY KEY (profile_identity, profile_type)                   \n \
+      PRIMARY KEY (profile_type)                                     \n \
   );                                                                 \n \
                                                                      \
-CREATE INDEX sp_index ON SelfProfile(profile_identity,profile_type); \n \
-";
+CREATE INDEX sp_index ON SelfProfile(profile_type);                  \n \
+"; // user's own profile;
 
 const string INIT_SE_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
@@ -43,21 +47,24 @@
       PRIMARY KEY (identity)                                         \n \
   );                                                                 \n \
 CREATE INDEX se_index ON SelfEndorse(identity);                      \n \
-";
+"; // user's self endorse cert;
 
 const string INIT_CONTACT_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
   Contact(                                                           \n \
       contact_namespace BLOB NOT NULL,                               \n \
       contact_alias     BLOB NOT NULL,                               \n \
-      self_certificate  BLOB NOT NULL,                               \n \
+      contact_keyName   BLOB NOT NULL,                               \n \
+      contact_key       BLOB NOT NULL,                               \n \
+      notBefore         INTEGER DEFAULT 0,                           \n \
+      notAfter          INTEGER DEFAULT 0,                           \n \
       is_introducer     INTEGER DEFAULT 0,                           \n \
                                                                      \
       PRIMARY KEY (contact_namespace)                                \n \
   );                                                                 \n \
                                                                      \
 CREATE INDEX contact_index ON Contact(contact_namespace);            \n \
-";
+"; // contact's basic info
 
 const string INIT_TS_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
@@ -68,7 +75,7 @@
   );                                                                 \n \
                                                                      \
 CREATE INDEX ts_index ON TrustScope(contact_namespace);              \n \
-";
+"; // contact's trust scope;
 
 const string INIT_CP_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
@@ -82,7 +89,7 @@
   );                                                                 \n \
                                                                      \
 CREATE INDEX cp_index ON ContactProfile(profile_identity);           \n \
-";
+"; // contact's profile
 
 const string INIT_PE_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
@@ -94,28 +101,40 @@
   );                                                                 \n \
                                                                      \
 CREATE INDEX pe_index ON ProfileEndorse(identity);                   \n \
-";
+"; // user's endorsement on contacts
 
 const string INIT_CE_TABLE = "\
 CREATE TABLE IF NOT EXISTS                                           \n \
   CollectEndorse(                                                    \n \
-      endorsee          BLOB NOT NULL,                               \n \
       endorser          BLOB NOT NULL,                               \n \
       endorse_name      BLOB NOT NULL,                               \n \
       endorse_data      BLOB NOT NULL,                               \n \
                                                                      \
-      PRIMARY KEY (endorsee, endorser)                               \n \
+      PRIMARY KEY (endorser)                                         \n \
   );                                                                 \n \
-                                                                     \
-CREATE INDEX ce_index ON CollectEndorse(endorsee);                   \n \
-";
+"; // contact's endorsements on the user
 
-ContactStorage::ContactStorage()
+const string INIT_DD_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  DnsData(                                                           \n \
+      dns_name      BLOB NOT NULL,                                   \n \
+      dns_type      BLOB NOT NULL,                                   \n \
+      data_name     BLOB NOT NULL,                                   \n	\
+      dns_value     BLOB NOT NULL,                                   \n \
+                                                                     \
+      PRIMARY KEY (dns_name, dns_type)                               \n \
+  );                                                                 \
+CREATE INDEX dd_index ON DnsData(dns_name, dns_type);                \n \
+CREATE INDEX dd_index2 ON DnsData(data_name);                        \n \
+"; // dns data;
+
+ContactStorage::ContactStorage(const Name& identity)
+  : m_identity(identity)
 {
   fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
   fs::create_directories (chronosDir);
 
-  int res = sqlite3_open((chronosDir / "chronos.db").c_str (), &m_db);
+  int res = sqlite3_open((chronosDir / getDBName()).c_str (), &m_db);
   if (res != SQLITE_OK)
     throw Error("Chronos DB cannot be open/created");
 
@@ -126,9 +145,28 @@
   initializeTable("ContactProfile", INIT_CP_TABLE);
   initializeTable("ProfileEndorse", INIT_PE_TABLE);
   initializeTable("CollectEndorse", INIT_CE_TABLE);
+  initializeTable("DnsData", INIT_DD_TABLE);
 
 }
 
+string
+ContactStorage::getDBName()
+{
+  string dbName("chronos-");
+
+  stringstream ss;
+  {
+    using namespace CryptoPP;
+
+    SHA256 hash;
+    StringSource(m_identity.wireEncode().wire(), m_identity.wireEncode().size(), true,
+                 new HashFilter(hash, new HexEncoder(new FileSink(ss), false)));
+  }
+  dbName.append(ss.str()).append(".db");
+
+  return dbName;
+}
+
 void
 ContactStorage::initializeTable(const string& tableName, const string& sqlCreateStmt)
 {
@@ -152,16 +190,14 @@
 }
 
 shared_ptr<Profile>
-ContactStorage::getSelfProfile(const Name& identity) const
+ContactStorage::getSelfProfile()
 {  
-  shared_ptr<Profile> profile;
+  shared_ptr<Profile> profile = make_shared<Profile>(m_identity);
   sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "SELECT profile_type, profile_value FROM SelfProfile WHERE profile_identity=?", -1, &stmt, 0);
-  sqlite3_bind_text (stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_prepare_v2 (m_db, "SELECT profile_type, profile_value FROM SelfProfile", -1, &stmt, 0);
 
   while( sqlite3_step (stmt) == SQLITE_ROW)
     {
-      profile = make_shared<Profile>(identity);
       string profileType(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
       string profileValue(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1));
       (*profile)[profileType] = profileValue;
@@ -172,61 +208,20 @@
   return profile;
 }
 
-// Block
-// ContactStorage::getSelfEndorseCertificate(const Name& identity)
-// {
-//   sqlite3_stmt *stmt;
-//   sqlite3_prepare_v2 (m_db, "SELECT endorse_data FROM SelfEndorse where identity=?", -1, &stmt, 0);
-//   sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
-
-//   if(sqlite3_step (stmt) == SQLITE_ROW)
-//     {
-//       Block result(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
-//       sqlite3_finalize (stmt);
-//       return result;
-//     }
-
-//   sqlite3_finalize (stmt);
-
-//   throw Error("ContactStorage: No self-endorse certificate found!");
-// }
-
 void
-ContactStorage::addSelfEndorseCertificate(const EndorseCertificate& newEndorseCertificate, const Name& identity)
+ContactStorage::addSelfEndorseCertificate(const EndorseCertificate& newEndorseCertificate)
 {
   const Block& newEndorseCertificateBlock = newEndorseCertificate.wireEncode();
 
   sqlite3_stmt *stmt;
   sqlite3_prepare_v2 (m_db, "INSERT OR REPLACE INTO SelfEndorse (identity, endorse_data) values (?, ?)", -1, &stmt, 0);
-  sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 1, m_identity.toUri().c_str(), m_identity.toUri().size(), SQLITE_TRANSIENT);
   sqlite3_bind_text(stmt, 2, reinterpret_cast<const char*>(newEndorseCertificateBlock.wire()), newEndorseCertificateBlock.size(), SQLITE_TRANSIENT);
-  sqlite3_step(stmt);
+  int res = sqlite3_step(stmt);
 
   sqlite3_finalize (stmt);
 }
 
-// Block
-// ContactStorage::getEndorseCertificate(const Name& identity)
-// {
-//   sqlite3_stmt *stmt;
-//   sqlite3_prepare_v2 (m_db, "SELECT endorse_data FROM ProfileEndorse where identity=?", -1, &stmt, 0);
-//   sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
-
-  
-//   if(sqlite3_step (stmt) == SQLITE_ROW)
-//     {
-//       Block result(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
-//       sqlite3_finalize (stmt);
-//       return result;
-//     }
-
-//   sqlite3_finalize (stmt);
-
-//   throw Error("ContactStorage: No endorse certificate found!");
-  
-//   return Block();
-// }
-
 void
 ContactStorage::addEndorseCertificate(const EndorseCertificate& endorseCertificate, const Name& identity)
 {
@@ -235,7 +230,7 @@
   sqlite3_stmt *stmt;
   sqlite3_prepare_v2 (m_db, "INSERT OR REPLACE INTO ProfileEndorse (identity, endorse_data) values (?, ?)", -1, &stmt, 0);
   sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
-  sqlite3_bind_text(stmt, 2, reinterpret_cast<const char*>(newEndorseCertificateBlock.value()), newEndorseCertificateBlock.size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, reinterpret_cast<const char*>(newEndorseCertificateBlock.wire()), newEndorseCertificateBlock.size(), SQLITE_TRANSIENT);
   sqlite3_step(stmt);
 
   sqlite3_finalize (stmt);
@@ -245,33 +240,39 @@
 ContactStorage::updateCollectEndorse(const EndorseCertificate& endorseCertificate)
 {
   Name endorserName = endorseCertificate.getSigner();
-  Name keyName = endorseCertificate.getPublicKeyName();
-  Name endorseeName = keyName.getPrefix(keyName.size()-1);
-  Name getCertName = endorseCertificate.getName();
+  Name certName = endorseCertificate.getName();
 
   sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "INSERT OR REPLACE INTO CollectEndorse (endorser, endorsee, endorse_name, endorse_data) VALUES (?, ?, ?, ?)", -1, &stmt, 0);
+  sqlite3_prepare_v2 (m_db, "INSERT OR REPLACE INTO CollectEndorse (endorser, endorse_name, endorse_data) VALUES (?, ?, ?, ?)", -1, &stmt, 0);
   sqlite3_bind_text(stmt, 1, endorserName.toUri().c_str(), endorserName.toUri().size(), SQLITE_TRANSIENT);
-  sqlite3_bind_text(stmt, 2, endorseeName.toUri().c_str(), endorseeName.toUri().size(), SQLITE_TRANSIENT);
-  sqlite3_bind_text(stmt, 3, getCertName.toUri().c_str(), getCertName.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, certName.toUri().c_str(), certName.toUri().size(), SQLITE_TRANSIENT);
   const Block &block = endorseCertificate.wireEncode();
-  sqlite3_bind_text(stmt, 4, reinterpret_cast<const char*>(block.wire()), block.size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 3, reinterpret_cast<const char*>(block.wire()), block.size(), SQLITE_TRANSIENT);
   int res = sqlite3_step (stmt);
   sqlite3_finalize (stmt); 
   return;
 }
 
 void
-ContactStorage::getCollectEndorseList(const Name& name, vector<Buffer>& endorseList)
+ContactStorage::getCollectEndorse(EndorseCollection& endorseCollection)
 {
   sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "SELECT endorse_data FROM CollectEndorse WHERE endorsee=?", -1, &stmt, 0);
-  sqlite3_bind_text(stmt, 1, name.toUri().c_str(), name.toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_prepare_v2 (m_db, "SELECT endorse_name, endorse_data FROM CollectEndorse", -1, &stmt, 0);
 
   while(sqlite3_step (stmt) == SQLITE_ROW)
     {
-      Buffer blob(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
-      endorseList.push_back(blob);
+      string certName(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 1));
+      stringstream ss;
+      {
+        using namespace CryptoPP;
+        SHA256 hash;
+
+        StringSource(sqlite3_column_text(stmt, 1), sqlite3_column_bytes (stmt, 0), true,
+                     new HashFilter(hash, new FileSink(ss)));
+      }
+      EndorseCollection::Endorsement* endorsement = endorseCollection.add_endorsement();
+      endorsement->set_certname(certName);
+      endorsement->set_hash(ss.str());
     }
 
   sqlite3_finalize (stmt);
@@ -294,9 +295,9 @@
 
 
 void 
-ContactStorage::removeContact(const Name& contactNameSpace)
+ContactStorage::removeContact(const Name& identityName)
 {
-  string identity = contactNameSpace.toUri();
+  string identity = identityName.toUri();
   
   sqlite3_stmt *stmt;  
   sqlite3_prepare_v2 (m_db, "DELETE FROM Contact WHERE contact_namespace=?", -1, &stmt, 0);
@@ -316,32 +317,38 @@
 }
   
 void
-ContactStorage::addContact(const ContactItem& contact)
+ContactStorage::addContact(const Contact& contact)
 {
   if(doesContactExist(contact.getNameSpace()))
     throw Error("Normal Contact has already existed");
 
+  string identity = contact.getNameSpace().toUri();
   bool isIntroducer = contact.isIntroducer();
 
   sqlite3_stmt *stmt;  
   sqlite3_prepare_v2 (m_db, 
-                      "INSERT INTO Contact (contact_namespace, contact_alias, self_certificate, is_introducer) values (?, ?, ?, ?)", 
-                      -1, 
-                      &stmt, 
+                      "INSERT INTO Contact (contact_namespace, contact_alias, contact_keyName, contact_key, notBefore, notAfter, is_introducer) values (?, ?, ?, ?, ?, ?, ?)", 
+                      -1,
+                      &stmt,
                       0);
 
-  sqlite3_bind_text(stmt, 1, contact.getNameSpace().toUri().c_str(),  contact.getNameSpace().toUri().size (), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 1, identity.c_str(), identity.size (), SQLITE_TRANSIENT);
   sqlite3_bind_text(stmt, 2, contact.getAlias().c_str(), contact.getAlias().size(), SQLITE_TRANSIENT);
-  const Block& selfCertificateBlock = contact.getSelfEndorseCertificate().wireEncode();
-  sqlite3_bind_text(stmt, 3, reinterpret_cast<const char*>(selfCertificateBlock.wire()), selfCertificateBlock.size(), SQLITE_TRANSIENT);
-  sqlite3_bind_int(stmt, 4, (isIntroducer ? 1 : 0));
+  sqlite3_bind_text(stmt, 3, contact.getPublicKeyName().toUri().c_str(), contact.getPublicKeyName().toUri().size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 4, reinterpret_cast<const char*>(contact.getPublicKey().get().buf()), contact.getPublicKey().get().size(), SQLITE_TRANSIENT);
+  sqlite3_bind_int64(stmt, 5, contact.getNotBefore());
+  sqlite3_bind_int64(stmt, 6, contact.getNotAfter());
+  sqlite3_bind_int(stmt, 7, (isIntroducer ? 1 : 0));
 
   int res = sqlite3_step (stmt);
+
+  // _LOG_DEBUG("addContact: " << res);
+
   sqlite3_finalize (stmt);
 
-  const Profile&  profile = contact.getSelfEndorseCertificate().getProfile();
+  const Profile& profile = contact.getProfile();
   Profile::const_iterator it = profile.begin();
-  string identity = contact.getNameSpace().toUri();
+
   for(; it != profile.end(); it++)
     {
       sqlite3_prepare_v2 (m_db, 
@@ -358,17 +365,17 @@
 
   if(isIntroducer)
     {
-      ContactItem::const_iterator it = contact.trustScopeBegin();
-      string nameSpace = contact.getNameSpace().toUri();
-      
-      while(it != contact.trustScopeEnd())
+      Contact::const_iterator it  = contact.trustScopeBegin();
+      Contact::const_iterator end = contact.trustScopeEnd();
+
+      while(it != end)
         {
           sqlite3_prepare_v2 (m_db, 
                               "INSERT INTO TrustScope (contact_namespace, trust_scope) values (?, ?)", 
                               -1, 
                               &stmt, 
                               0);
-          sqlite3_bind_text(stmt, 1, nameSpace.c_str(),  nameSpace.size (), SQLITE_TRANSIENT);
+          sqlite3_bind_text(stmt, 1, identity.c_str(), identity.size (), SQLITE_TRANSIENT);
           sqlite3_bind_text(stmt, 2, it->first.toUri().c_str(), it->first.toUri().size(), SQLITE_TRANSIENT);
           res = sqlite3_step (stmt);
           sqlite3_finalize (stmt);          
@@ -378,43 +385,55 @@
 }
 
 
-shared_ptr<ContactItem>
-ContactStorage::getContact(const Name& name)
+shared_ptr<Contact>
+ContactStorage::getContact(const Name& identity) const
 {
+  shared_ptr<Contact> contact;
+  Profile profile;
+
   sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "SELECT contact_alias, self_certificate, is_introducer FROM Contact where contact_namespace=?", -1, &stmt, 0);
-  sqlite3_bind_text (stmt, 1, name.toUri().c_str(), name.toUri().size(), SQLITE_TRANSIENT);
-  
-  if( sqlite3_step (stmt) == SQLITE_ROW)
+  sqlite3_prepare_v2 (m_db, "SELECT contact_alias, contact_keyName, contact_key, notBefore, notAfter, is_introducer FROM Contact where contact_namespace=?", -1, &stmt, 0);
+  sqlite3_bind_text (stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+
+  if(sqlite3_step (stmt) == SQLITE_ROW)
     {
-      string alias(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      string alias(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      string keyName(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1));
+      PublicKey key(sqlite3_column_text(stmt, 2), sqlite3_column_bytes (stmt, 2));
+      int64_t notBefore = sqlite3_column_int64 (stmt, 3);
+      int64_t notAfter = sqlite3_column_int64 (stmt, 4);
+      int isIntroducer = sqlite3_column_int (stmt, 5);
 
-      Data certData;
-      certData.wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1)));
-      EndorseCertificate endorseCertificate(certData);
+      contact = shared_ptr<Contact>(new Contact(identity, alias, Name(keyName), notBefore, notAfter, key, isIntroducer));
+    }
+  sqlite3_finalize (stmt);
 
-      int isIntroducer = sqlite3_column_int (stmt, 2);
+  sqlite3_prepare_v2 (m_db, "SELECT profile_type, profile_value FROM ContactProfile where profile_identity=?", -1, &stmt, 0);
+  sqlite3_bind_text (stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
+  
+  while(sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      string type(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      string value(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1));
+      profile[type] = value;
+    }
+  sqlite3_finalize (stmt);
+  contact->setProfile(profile);
 
-      sqlite3_finalize (stmt);
-      
-      shared_ptr<ContactItem> contact = make_shared<ContactItem>(endorseCertificate, isIntroducer, alias);
+  if(contact->isIntroducer())
+    {
+      sqlite3_prepare_v2 (m_db, "SELECT trust_scope FROM TrustScope WHERE contact_namespace=?", -1, &stmt, 0);
+      sqlite3_bind_text(stmt, 1, identity.toUri().c_str(), identity.toUri().size(), SQLITE_TRANSIENT);
 
-      if(contact->isIntroducer())
+      while(sqlite3_step (stmt) == SQLITE_ROW)
         {
-          sqlite3_prepare_v2 (m_db, "SELECT trust_scope FROM TrustScope WHERE contact_namespace=?", -1, &stmt, 0);
-          sqlite3_bind_text(stmt, 1, name.toUri().c_str(), name.toUri().size(), SQLITE_TRANSIENT);
-
-          while( sqlite3_step (stmt) == SQLITE_ROW)
-            {
-              Name scope(string(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
-              contact->addTrustScope(scope);
-            }
-          sqlite3_finalize (stmt);  
+          Name scope(string(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
+          contact->addTrustScope(scope);
         }
+      sqlite3_finalize (stmt);
+    }
 
-      return contact;      
-    } 
-  return shared_ptr<ContactItem>();
+  return contact;
 }
 
 
@@ -464,41 +483,85 @@
 }
 
 void
-ContactStorage::getAllContacts(vector<shared_ptr<ContactItem> >& contacts) const
+ContactStorage::getAllContacts(vector<shared_ptr<Contact> >& contacts) const
 {
+  vector<Name> contactNames;
+
   sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "SELECT contact_alias, self_certificate, is_introducer FROM Contact", -1, &stmt, 0);
+  sqlite3_prepare_v2 (m_db, "SELECT contact_namespace FROM Contact", -1, &stmt, 0);
   
-  while( sqlite3_step (stmt) == SQLITE_ROW)
+  while(sqlite3_step (stmt) == SQLITE_ROW)
     {
-      string alias(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
-
-      Data certData;
-      certData.wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1)));
-      EndorseCertificate endorseCertificate(certData);
-
-      int isIntroducer = sqlite3_column_int (stmt, 2);
-
-      contacts.push_back(make_shared<ContactItem>(endorseCertificate, isIntroducer, alias));      
+      string identity(reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes(stmt, 0));
+      contactNames.push_back(Name(identity));
     }
-  sqlite3_finalize (stmt);  
+  sqlite3_finalize (stmt);
 
-  vector<shared_ptr<ContactItem> >::iterator it = contacts.begin();
-  for(; it != contacts.end(); it++)
+  vector<Name>::iterator it  = contactNames.begin();
+  vector<Name>::iterator end = contactNames.end();
+  for(; it != end; it++)
     {
-      if((*it)->isIntroducer())
-        {
-          sqlite3_prepare_v2 (m_db, "SELECT trust_scope FROM TrustScope WHERE contact_namespace=?", -1, &stmt, 0);
-          sqlite3_bind_text(stmt, 1, (*it)->getNameSpace().toUri().c_str(), (*it)->getNameSpace().toUri().size(), SQLITE_TRANSIENT);
-
-          while( sqlite3_step (stmt) == SQLITE_ROW)
-            {
-              Name scope(string(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
-              (*it)->addTrustScope(scope);
-            }
-          sqlite3_finalize (stmt);  
-        }
+      shared_ptr<Contact> contact = getContact(*it);
+      if(static_cast<bool>(contact))
+        contacts.push_back(contact);
     }
 }
 
+void
+ContactStorage::updateDnsData(const Block& data, 
+                              const string& name, 
+                              const string& type, 
+                              const string& dataName)
+{  
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "INSERT OR REPLACE INTO DnsData (dns_name, dns_type, dns_value, data_name) VALUES (?, ?, ?, ?)", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, name.c_str(), name.size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, type.c_str(), type.size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 3, reinterpret_cast<const char*>(data.wire()), data.size(), SQLITE_TRANSIENT); 
+  sqlite3_bind_text(stmt, 4, dataName.c_str(), dataName.size(), SQLITE_TRANSIENT);
+  int res = sqlite3_step(stmt);
+
+  // _LOG_DEBUG("updateDnsData " << res);
+  sqlite3_finalize(stmt);
+}
+
+shared_ptr<Data>
+ContactStorage::getDnsData(const Name& dataName)
+{
+  shared_ptr<Data> data;
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT dns_value FROM DnsData where data_name=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, dataName.toUri().c_str(), dataName.toUri().size(), SQLITE_TRANSIENT);
+  
+  if(sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      data = make_shared<Data>();
+      data->wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
+    }
+  sqlite3_finalize(stmt);
+
+  return data;
+}
+
+shared_ptr<Data>
+ContactStorage::getDnsData(const string& name, const string& type)
+{
+  shared_ptr<Data> data;
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT dns_value FROM DnsData where dns_name=? and dns_type=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, name.c_str(), name.size(), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, type.c_str(), type.size(), SQLITE_TRANSIENT);
+  
+  if(sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      data = make_shared<Data>();
+      data->wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
+    }
+  sqlite3_finalize(stmt);
+
+  return data;
+}
+
 }//chronos
diff --git a/src/contact-storage.h b/src/contact-storage.h
index da6c812..5662ebb 100644
--- a/src/contact-storage.h
+++ b/src/contact-storage.h
@@ -11,7 +11,8 @@
 #ifndef CHRONOS_CONTACT_STORAGE_H
 #define CHRONOS_CONTACT_STORAGE_H
 
-#include "contact-item.h"
+#include "contact.h"
+#include "endorse-collection.pb.h"
 #include <sqlite3.h>
 
 
@@ -23,22 +24,18 @@
 public:
   struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
 
-  ContactStorage();
+  ContactStorage(const ndn::Name& identity);
   
   ~ContactStorage() 
-  { sqlite3_close(m_db); }
+  {
+    sqlite3_close(m_db); 
+  }
 
   ndn::shared_ptr<Profile>
-  getSelfProfile(const ndn::Name& identity) const;
-
-  // ndn::Block
-  // getSelfEndorseCertificate(const ndn::Name& identity);
+  getSelfProfile();
   
   void
-  addSelfEndorseCertificate(const EndorseCertificate& endorseCertificate, const ndn::Name& identity);
-
-  // ndn::Block
-  // getEndorseCertificate(const ndn::Name& identity);
+  addSelfEndorseCertificate(const EndorseCertificate& endorseCertificate);
 
   void
   addEndorseCertificate(const EndorseCertificate& endorseCertificate, const ndn::Name& identity);
@@ -47,7 +44,7 @@
   updateCollectEndorse(const EndorseCertificate& endorseCertificate);
 
   void
-  getCollectEndorseList(const ndn::Name& name, std::vector<ndn::Buffer>& endorseList);
+  getCollectEndorse(EndorseCollection& endorseCollection);
 
   void
   getEndorseList(const ndn::Name& identity, std::vector<std::string>& endorseList);
@@ -58,10 +55,10 @@
   removeContact(const ndn::Name& identity);
 
   void
-  addContact(const ContactItem& contactItem);
+  addContact(const Contact& contact);
 
-  ndn::shared_ptr<ContactItem>
-  getContact(const ndn::Name& name);
+  ndn::shared_ptr<Contact>
+  getContact(const ndn::Name& identity) const;
 
   void
   updateIsIntroducer(const ndn::Name& identity, bool isIntroducer);
@@ -70,19 +67,48 @@
   updateAlias(const ndn::Name& identity, std::string alias);
 
   void
-  getAllContacts(std::vector<ndn::shared_ptr<ContactItem> >& contacts) const;
+  getAllContacts(std::vector<ndn::shared_ptr<Contact> >& contacts) const;
 
- 
+  void
+  updateDnsSelfProfileData(const ndn::Data& data)
+  {
+    updateDnsData(data.wireEncode(), "N/A", "PROFILE", data.getName().toUri());
+  }
+
+  void
+  updateDnsEndorseOthers(const ndn::Data& data, const std::string& endorsee)
+  {
+    updateDnsData(data.wireEncode(), endorsee, "ENDORSEE", data.getName().toUri());
+  }
   
+  void
+  updateDnsOthersEndorse(const ndn::Data& data)
+  {
+    updateDnsData(data.wireEncode(), "N/A", "ENDORSED", data.getName().toUri()); 
+  }
+
+  ndn::shared_ptr<ndn::Data>
+  getDnsData(const ndn::Name& name);
+
+  ndn::shared_ptr<ndn::Data>
+  getDnsData(const std::string& name, const std::string& type);
 
 private:
+  std::string
+  getDBName();
+  
   void
   initializeTable(const std::string& tableName, const std::string& sqlCreateStmt);
 
   bool
   doesContactExist(const ndn::Name& name);
 
+  void
+  updateDnsData(const ndn::Block& data, const std::string& name, const std::string& type, const std::string& dataName);
+
 private:
+  ndn::Name m_identity;
+
   sqlite3 *m_db;
 };
 
diff --git a/src/contact.h b/src/contact.h
new file mode 100644
index 0000000..4960972
--- /dev/null
+++ b/src/contact.h
@@ -0,0 +1,238 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHRONOS_CONTACT_H
+#define CHRONOS_CONTACT_H
+
+#include <ndn-cpp-dev/security/identity-certificate.hpp>
+#include <ndn-cpp-dev/util/regex.hpp>
+#include "endorse-certificate.h"
+#include <vector>
+
+namespace chronos{
+
+class Contact
+{
+public:
+  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::const_iterator const_iterator;
+  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::iterator iterator;
+
+  Contact(const ndn::IdentityCertificate& identityCertificate,
+          bool isIntroducer = false,
+          const std::string& alias = "")
+    : m_notBefore(identityCertificate.getNotBefore())
+    , m_notAfter(identityCertificate.getNotAfter())
+    , m_isIntroducer(isIntroducer)
+    , m_profile(identityCertificate)
+  {
+    m_name = m_profile.get("name");
+    m_alias = alias.empty() ? m_name : alias;
+    m_institution = m_profile.get("institution");
+    
+    m_keyName = identityCertificate.getPublicKeyName();
+    m_namespace = m_keyName.getPrefix(-1);
+    m_publicKey = identityCertificate.getPublicKeyInfo();
+  }
+
+  Contact(const EndorseCertificate& endorseCertificate,
+          bool isIntroducer = false,
+          const std::string& alias = "")
+    : m_notBefore(endorseCertificate.getNotBefore())
+    , m_notAfter(endorseCertificate.getNotAfter())
+    , m_isIntroducer(isIntroducer)
+  { 
+    m_profile = endorseCertificate.getProfile();
+    
+    m_name = m_profile.get("name");
+    m_alias = alias.empty() ? m_name : alias;
+    m_institution = m_profile.get("institution");
+    
+    m_keyName = endorseCertificate.getPublicKeyName();;
+    m_namespace = m_keyName.getPrefix(-1);
+    m_publicKey = endorseCertificate.getPublicKeyInfo();
+  }
+
+  Contact(const ndn::Name& identity,
+          const std::string& alias,
+          const ndn::Name& keyName,
+          ndn::MillisecondsSince1970 notBefore,
+          ndn::MillisecondsSince1970 notAfter,
+          const ndn::PublicKey& key,
+          bool isIntroducer)
+    : m_namespace(identity)
+    , m_alias(alias)
+    , m_keyName(keyName)
+    , m_publicKey(key)
+    , m_notBefore(notBefore)
+    , m_notAfter(notAfter)
+    , m_isIntroducer(isIntroducer)
+  {
+  }
+  
+  Contact(const Contact& contact)
+    : m_namespace(contact.m_namespace)
+    , m_alias(contact.m_alias)
+    , m_name(contact.m_name)
+    , m_institution(contact.m_institution)
+    , m_keyName(contact.m_keyName)
+    , m_publicKey(contact.m_publicKey)
+    , m_notBefore(contact.m_notBefore)
+    , m_notAfter(contact.m_notAfter)
+    , m_isIntroducer(contact.m_isIntroducer)
+    , m_profile(contact.m_profile)
+    , m_trustScope(contact.m_trustScope)
+  {}
+  
+  virtual
+  ~Contact()
+  {}
+
+  const ndn::Name&
+  getNameSpace() const
+  {
+    return m_namespace;
+  }
+
+  const std::string&
+  getAlias() const
+  {
+    return m_alias;
+  }
+
+  const std::string&
+  getName() const
+  {
+    return m_name;
+  }
+
+  const std::string&
+  getInstitution() const
+  {
+    return m_institution;
+  }
+
+  const ndn::Name&
+  getPublicKeyName() const
+  {
+    return m_keyName; 
+  }
+
+  const ndn::PublicKey&
+  getPublicKey() const
+  {
+    return m_publicKey;
+  }
+
+  ndn::MillisecondsSince1970
+  getNotBefore() const
+  {
+    return m_notBefore;
+  }
+
+  ndn::MillisecondsSince1970
+  getNotAfter() const
+  {
+    return m_notAfter;
+  }
+
+  const Profile&
+  getProfile() const
+  {
+    return m_profile;
+  }
+
+  void
+  setProfile(const Profile& profile)
+  {
+    m_name = profile.get("name");
+    m_institution = profile.get("institution");
+    m_profile = profile;
+  }
+
+  bool
+  isIntroducer() const
+  {
+    return m_isIntroducer;
+  }
+
+  void
+  setIsIntroducer(bool isIntroducer) 
+  { 
+    m_isIntroducer = isIntroducer; 
+  }
+
+  void
+  addTrustScope(const ndn::Name& nameSpace)
+  { 
+    m_trustScope[nameSpace] = ndn::Regex::fromName(nameSpace); 
+  }
+
+  void
+  deleteTrustScope(const ndn::Name& nameSpace)
+  {
+    m_trustScope.erase(nameSpace);
+  }
+
+  bool
+  canBeTrustedFor(const ndn::Name& name)
+  {
+    std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> >::iterator it = m_trustScope.begin();
+
+    for(; it != m_trustScope.end(); it++)
+      if(it->second->match(name))
+        return true;
+    return false;
+  }
+
+  const_iterator
+  trustScopeBegin() const
+  {
+    return m_trustScope.begin();
+  }
+
+  const_iterator
+  trustScopeEnd() const
+  {
+    return m_trustScope.end();
+  }
+
+  iterator
+  trustScopeBegin()
+  {
+    return m_trustScope.begin();
+  }
+
+  iterator
+  trustScopeEnd()
+  {
+    return m_trustScope.end();
+  }
+
+protected:
+  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::Regex> > TrustScopes;
+
+  ndn::Name m_namespace;
+  std::string m_alias;
+  std::string m_name;
+  std::string m_institution;
+  ndn::Name m_keyName;
+  ndn::PublicKey m_publicKey;
+  ndn::MillisecondsSince1970 m_notBefore;
+  ndn::MillisecondsSince1970 m_notAfter;
+
+  bool m_isIntroducer;
+  Profile m_profile;
+  
+  TrustScopes m_trustScope;
+};
+
+} // namespace chronos
+
+#endif // CHRONOS_CONTACT_H
diff --git a/src/contactpanel.cpp b/src/contactpanel.cpp
deleted file mode 100644
index 413f32b..0000000
--- a/src/contactpanel.cpp
+++ /dev/null
@@ -1,828 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "contactpanel.h"
-#include "ui_contactpanel.h"
-
-
-#include <QStringList>
-#include <QItemSelectionModel>
-#include <QModelIndex>
-#include <QDir>
-#include <QtSql/QSqlRecord>
-#include <QtSql/QSqlField>
-#include <QtSql/QSqlError>
-
-#ifndef Q_MOC_RUN
-#include <ndn-cpp-dev/security/validator.hpp>
-#include <ndn-cpp-dev/security/signature-sha256-with-rsa.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/random/random_device.hpp>
-#include <boost/random/uniform_int_distribution.hpp>
-#include "logging.h"
-#endif
-
-namespace fs = boost::filesystem;
-using namespace ndn;
-using namespace chronos;
-using namespace std;
-
-INIT_LOGGER("ContactPanel");
-
-Q_DECLARE_METATYPE(ndn::IdentityCertificate)
-
-ContactPanel::ContactPanel(shared_ptr<Face> face,
-                           QWidget *parent) 
-  : QDialog(parent)
-  , ui(new Ui::ContactPanel)
-  , m_warningDialog(new WarningDialog)
-  , m_contactListModel(new QStringListModel)
-  , m_startChatDialog(new StartChatDialog)
-  , m_invitationDialog(new InvitationDialog)
-  , m_settingDialog(new SettingDialog)
-  , m_keyChain(new KeyChain)
-  , m_face(face)
-  , m_ioService(face->ioService())
-  , m_contactManager(new ContactManager(m_face))
-{
-
-  qRegisterMetaType<ndn::IdentityCertificate>("IdentityCertificate");
-
-  createAction();
-
-#ifdef WITH_SECURITY
-  m_panelValidator = make_shared<chronos::ValidatorPanel>();
-  m_invitationValidator = make_shared<chronos::ValidatorInvitation>();
-#else
-  m_panelValidator = make_shared<ndn::ValidatorNull>();
-  m_invitationValidator = make_shared<ndn::ValidatorNull>();
-#endif
-
-  connect(&*m_contactManager, SIGNAL(noNdnConnection(const QString&)),
-          this, SLOT(showError(const QString&)));
-  
-  openDB();    
-
-  refreshContactList();
-
-  loadTrustAnchor();
-
-  m_defaultIdentity = m_keyChain->getDefaultIdentity();
-
-  if(m_defaultIdentity.size() == 0)
-    showError(QString::fromStdString("certificate of ") + QString::fromStdString(m_defaultIdentity.toUri()) + " is missing!\nHave you installed the certificate?");
-
-  m_keyChain->createIdentity(m_defaultIdentity);
-
-  m_contactManager->setDefaultIdentity(m_defaultIdentity);
-  m_nickName = m_defaultIdentity.get(-1).toEscapedString();
-  m_settingDialog->setIdentity(m_defaultIdentity.toUri(), m_nickName);
-  
-
-  m_profileEditor = new ProfileEditor(m_contactManager);
-  m_profileEditor->setCurrentIdentity(m_defaultIdentity);
-
-  m_addContactPanel = new AddContactPanel(m_contactManager);
-  m_browseContactDialog = new BrowseContactDialog(m_contactManager);
-  m_setAliasDialog = new SetAliasDialog(m_contactManager);
- 
-  ui->setupUi(this);
-
-  
-  m_localPrefix = Name("/private/local");
-  setLocalPrefix();
-    
-  setInvitationListener();
-
-  collectEndorsement();
-  
-  ui->ContactList->setModel(m_contactListModel);
-  
-
-  connect(ui->ContactList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
-          this, SLOT(updateSelection(const QItemSelection &, const QItemSelection &)));
-
-  connect(ui->ContactList, SIGNAL(customContextMenuRequested(const QPoint&)),
-          this, SLOT(showContextMenu(const QPoint&)));
-
-  connect(ui->EditProfileButton, SIGNAL(clicked()), 
-          this, SLOT(openProfileEditor()));
-
-  connect(m_profileEditor, SIGNAL(noKeyOrCert(const QString&)),
-          this, SLOT(showWarning(const QString&)));
-
-  connect(ui->AddContactButton, SIGNAL(clicked()),
-          this, SLOT(openBrowseContactDialog()));
-
-  connect(m_browseContactDialog, SIGNAL(directAddClicked()),
-          this, SLOT(openAddContactPanel()));
-
-  connect(this, SIGNAL(refreshCertDirectory()),
-          m_browseContactDialog, SLOT(refreshList()));
-
-  connect(ui->DeleteContactButton, SIGNAL(clicked()),
-          this, SLOT(removeContactButton()));
-   
-  connect(ui->settingButton, SIGNAL(clicked()),
-          this, SLOT(openSettingDialog()));
-  
-  connect(ui->chatButton, SIGNAL(clicked()),
-          this, SLOT(openStartChatDialog()));
-   
-  connect(m_addContactPanel, SIGNAL(newContactAdded()),
-          this, SLOT(refreshContactList()));
-  connect(m_browseContactDialog, SIGNAL(newContactAdded()),
-          this, SLOT(refreshContactList()));
-  connect(m_setAliasDialog, SIGNAL(aliasChanged()),
-          this, SLOT(refreshContactList()));
-
-  connect(m_startChatDialog, SIGNAL(chatroomConfirmed(const QString&)),
-          this, SLOT(startChatroom(const QString&)));
-
-  connect(m_invitationDialog, SIGNAL(invitationAccepted(const ndn::Name&)),
-          this, SLOT(acceptInvitation(const ndn::Name&)));
-  connect(m_invitationDialog, SIGNAL(invitationRejected(const ndn::Name&)),
-          this, SLOT(rejectInvitation(const ndn::Name&)));
-  
-  connect(&*m_contactManager, SIGNAL(contactAdded(const ndn::Name&)),
-          this, SLOT(addContactIntoValidator(const ndn::Name&)));
-  connect(&*m_contactManager, SIGNAL(contactRemoved(const ndn::Name&)),
-          this, SLOT(removeContactFromValidator(const ndn::Name&)));
-
-  connect(m_settingDialog, SIGNAL(identitySet(const QString&, const QString&)),
-          this, SLOT(updateDefaultIdentity(const QString&, const QString&)));
-
-  connect(ui->isIntroducer, SIGNAL(stateChanged(int)),
-          this, SLOT(isIntroducerChanged(int)));
-
-  connect(ui->addScope, SIGNAL(clicked()),
-          this, SLOT(addScopeClicked()));
-  connect(ui->deleteScope, SIGNAL(clicked()),
-          this, SLOT(deleteScopeClicked()));
-  connect(ui->saveButton, SIGNAL(clicked()),
-          this, SLOT(saveScopeClicked()));
-
-  connect(ui->endorseButton, SIGNAL(clicked()),
-          this, SLOT(endorseButtonClicked()));
-}
-
-ContactPanel::~ContactPanel()
-{
-  delete ui;
-  delete m_contactListModel;
-  delete m_startChatDialog;
-  delete m_invitationDialog;
-  delete m_settingDialog;
-
-  delete m_profileEditor;
-  delete m_addContactPanel;
-  delete m_browseContactDialog;
-  delete m_setAliasDialog;
-
-  delete m_trustScopeModel;
-  delete m_endorseDataModel;
-  delete m_endorseComboBoxDelegate;
-
-  delete m_menuAlias;
-
-  map<Name, ChatDialog*>::iterator it = m_chatDialogs.begin();
-  for(; it != m_chatDialogs.end(); it++)
-    delete it->second;
-}
-
-void
-ContactPanel::createAction()
-{
-  m_menuAlias = new QAction("&Set Alias", this);
-}
-
-void
-ContactPanel::openDB()
-{
-  QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
-  QString path = (QDir::home().path());
-  path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append("chronos.db");
-  db.setDatabaseName(path);
-  bool ok = db.open();
-  _LOG_DEBUG("DB opened: " << std::boolalpha << ok );
-
-  m_trustScopeModel = new QSqlTableModel;
-  m_endorseDataModel = new QSqlTableModel;
-  m_endorseComboBoxDelegate = new EndorseComboBoxDelegate;
-}
-
-void 
-ContactPanel::loadTrustAnchor()
-{
-#ifdef WITH_SECURITY
-  vector<shared_ptr<ContactItem> >::const_iterator it = m_contactList.begin();
-  for(; it != m_contactList.end(); it++)
-    {
-      _LOG_DEBUG("load contact: " << (*it)->getNameSpace().toUri());
-      m_invitationValidator->addTrustAnchor((*it)->getSelfEndorseCertificate());
-      m_panelValidator->addTrustAnchor((*it)->getSelfEndorseCertificate());
-    }
-#endif
-}
-
-void
-ContactPanel::setLocalPrefix(int retry)
-{
-  Name interestName("/local/ndn/prefix");
-  Interest interest(interestName);
-
-  m_face->expressInterest(interest, 
-                          bind(&ContactPanel::onLocalPrefix, this, _1, _2), 
-                          bind(&ContactPanel::onLocalPrefixTimeout, this, _1, 10));
-  
-}
-
-void
-ContactPanel::onLocalPrefix(const Interest& interest, Data& data)
-{
-  string originPrefix(reinterpret_cast<const char*>(data.getContent().value()), data.getContent().value_size());
-  string prefix = QString::fromStdString (originPrefix).trimmed ().toStdString();
-  m_localPrefix = Name(prefix);
-}
-
-void
-ContactPanel::onLocalPrefixTimeout(const Interest& interest, int retry)
-{ 
-  if(retry > 0)
-    {
-      setLocalPrefix(retry - 1);
-      return;
-    }
-  else
-    m_localPrefix = Name("/private/local");
-}
-
-void
-ContactPanel::setInvitationListener()
-{
-  m_inviteListenPrefix = Name("/ndn/broadcast/chronos/invitation");
-  m_inviteListenPrefix.append(m_defaultIdentity);
-  _LOG_DEBUG("Listening for invitation on prefix: " << m_inviteListenPrefix.toUri());
-  m_invitationListenerId = m_face->setInterestFilter(m_inviteListenPrefix, 
-                                                     bind(&ContactPanel::onInvitation, this, _1, _2),
-                                                     bind(&ContactPanel::onInvitationRegisterFailed, this, _1, _2));
-}
-
-void
-ContactPanel::sendInterest(const Interest& interest,
-                           const OnDataValidated& onValidated,
-                           const OnDataValidationFailed& onValidationFailed,
-                           const TimeoutNotify& timeoutNotify,
-                           int retry /* = 1 */)
-{
-  m_face->expressInterest(interest, 
-                          bind(&ContactPanel::onTargetData, 
-                               this, _1, _2, onValidated, onValidationFailed),
-                          bind(&ContactPanel::onTargetTimeout,
-                               this, _1, retry, onValidated, onValidationFailed, timeoutNotify));
-}
-
-void
-ContactPanel::onTargetData(const ndn::Interest& interest, 
-                           Data& data,
-                           const OnDataValidated& onValidated,
-                           const OnDataValidationFailed& onValidationFailed)
-{
-  m_panelValidator->validate(data, onValidated, onValidationFailed);
-}
-
-void
-ContactPanel::onTargetTimeout(const ndn::Interest& interest, 
-                              int retry,
-                              const OnDataValidated& onValidated,
-                              const OnDataValidationFailed& onValidationFailed,
-                              const TimeoutNotify& timeoutNotify)
-{
-  if(retry > 0)
-    sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, retry-1);
-  else
-    {
-      _LOG_DEBUG("Interest: " << interest.getName() << " eventually times out!");
-      timeoutNotify();
-    }
-}
-
-void
-ContactPanel::onInvitationRegisterFailed(const Name& prefix, const string& msg)
-{
-  showError(QString::fromStdString("Cannot register invitation listening prefix! " + msg));
-}
-
-void
-ContactPanel::onInvitation(const Name& prefix, const Interest& interest)
-{
-  _LOG_DEBUG("Receive invitation!" << interest.getName() << " " << prefix);
-
-  OnInterestValidated onValidated = bind(&ContactPanel::onInvitationValidated, this, _1);
-  OnInterestValidationFailed onValidationFailed = bind(&ContactPanel::onInvitationValidationFailed, this, _1);
-  m_invitationValidator->validate(interest, onValidated, onValidationFailed);
-}
-
-void
-ContactPanel::popChatInvitation(const Name& interestName)
-{
-  Invitation invitation(interestName);
-  string alias;
-
-  vector<shared_ptr<ContactItem> >::iterator it = m_contactList.begin();
-  for(; it != m_contactList.end(); it++)
-    if((*it)->getNameSpace() == invitation.getInviteeNameSpace())
-      alias = (*it)->getAlias();
-
-  if(it != m_contactList.end())
-    return;
-
-  m_invitationDialog->setInvitation(alias, interestName);
-  m_invitationDialog->show(); 
-}
-
-void
-ContactPanel::collectEndorsement()
-{
-#ifdef WITH_SECURITY
-  m_collectStatus = make_shared<vector<bool> >();
-  m_collectStatus->assign(m_contactList.size(), false);
-
-  vector<shared_ptr<ContactItem> >::iterator it = m_contactList.begin();
-  int count = 0;
-  for(; it != m_contactList.end(); it++, count++)
-    {
-      Name interestName = (*it)->getNameSpace();
-      interestName.append("DNS").append(m_defaultIdentity).append("ENDORSEE");
-      Interest interest(interestName);
-      interest.setInterestLifetime(1000);
-
-      OnDataValidated onValidated = bind(&ContactPanel::onDnsEndorseeValidated, this, _1, count);
-      OnDataValidationFailed onValidationFailed = bind(&ContactPanel::onDnsEndorseeValidationFailed, this, _1, count);
-      TimeoutNotify timeoutNotify = bind(&ContactPanel::onDnsEndorseeTimeoutNotify, this, count);
-  
-      sendInterest(interest, onValidated, onValidationFailed, timeoutNotify, 0);
-    }
-#endif
-}
-
-void
-ContactPanel::onDnsEndorseeValidated(const shared_ptr<const Data>& data, int count)
-{
-  Data endorseData;
-  endorseData.wireDecode(Block(data->getContent().value(), data->getContent().value_size()));
-  EndorseCertificate endorseCertificate(endorseData);
-
-  m_contactManager->getContactStorage()->updateCollectEndorse(endorseCertificate);
-
-  updateCollectStatus(count);
-}
-
-void
-ContactPanel::onDnsEndorseeTimeoutNotify(int count)
-{ updateCollectStatus(count); }
-
-void
-ContactPanel::onDnsEndorseeValidationFailed(const shared_ptr<const Data>& data, int count)
-{ updateCollectStatus(count); }
-
-void 
-ContactPanel::updateCollectStatus(int count)
-{
-  m_collectStatus->at(count) = true;
-  vector<bool>::const_iterator it = m_collectStatus->begin();
-  for(; it != m_collectStatus->end(); it++)
-    if(*it == false)
-      return;
-
-  m_contactManager->publishCollectEndorsedDataInDNS(m_defaultIdentity);
-}
-
-static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
-
-string
-ContactPanel::getRandomString()
-{
-  string randStr;
-  boost::random::random_device rng;
-  boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
-  for (int i = 0; i < 10; i ++)
-  {
-    randStr += chars[index_dist(rng)];
-  }
-  return randStr;
-}
-
-void
-ContactPanel::showError(const QString& msg){
-  QMessageBox::critical(this, tr("Chronos"), msg, QMessageBox::Ok);
-  exit(1);
-}
-
-void
-ContactPanel::showWarning(const QString& msg){
-  QMessageBox::information(this, tr("Chronos"), msg);
-}
-
-void
-ContactPanel::updateSelection(const QItemSelection &selected,
-			      const QItemSelection &deselected)
-{
-  QModelIndexList items = selected.indexes();
-  QString text = m_contactListModel->data(items.first(), Qt::DisplayRole).toString();
-  string alias = text.toStdString();
-
-  int i = 0;
-  for(; i < m_contactList.size(); i++)
-    {
-      if(alias == m_contactList[i]->getAlias())
-        break;
-    }
-  
-  m_currentSelectedContact = m_contactList[i];
-  ui->NameData->setText(QString::fromStdString(m_currentSelectedContact->getName()));
-  ui->NameSpaceData->setText(QString::fromStdString(m_currentSelectedContact->getNameSpace().toUri()));
-  ui->InstitutionData->setText(QString::fromStdString(m_currentSelectedContact->getInstitution()));
-
-  if(m_currentSelectedContact->isIntroducer())
-    {
-      ui->isIntroducer->setChecked(true);
-      ui->addScope->setEnabled(true);
-      ui->deleteScope->setEnabled(true);     
-      ui->trustScopeList->setEnabled(true);
-
-      string filter("contact_namespace = '");
-      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
-
-      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-      m_trustScopeModel->setTable("TrustScope");
-      m_trustScopeModel->setFilter(filter.c_str());
-      m_trustScopeModel->select();
-      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
-      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
-      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
-
-      ui->trustScopeList->setModel(m_trustScopeModel);
-      ui->trustScopeList->setColumnHidden(0, true);
-      ui->trustScopeList->setColumnHidden(1, true);
-      ui->trustScopeList->show();
-    }
-  else
-    {
-      ui->isIntroducer->setChecked(false);
-      ui->addScope->setEnabled(false);
-      ui->deleteScope->setEnabled(false);
-
-      string filter("contact_namespace = '");
-      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
-
-      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-      m_trustScopeModel->setTable("TrustScope");
-      m_trustScopeModel->setFilter(filter.c_str());
-      m_trustScopeModel->select();
-      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
-      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
-      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
-
-      ui->trustScopeList->setModel(m_trustScopeModel);
-      ui->trustScopeList->setColumnHidden(0, true);
-      ui->trustScopeList->setColumnHidden(1, true);
-      ui->trustScopeList->show();
-
-      ui->trustScopeList->setEnabled(false);
-    }
-
-  string filter("profile_identity = '");
-  filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
-
-  m_endorseDataModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-  m_endorseDataModel->setTable("ContactProfile");
-  m_endorseDataModel->setFilter(filter.c_str());
-  m_endorseDataModel->select();
-  
-  m_endorseDataModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Identity"));
-  m_endorseDataModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Type"));
-  m_endorseDataModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Value"));
-  m_endorseDataModel->setHeaderData(3, Qt::Horizontal, QObject::tr("Endorse"));
-
-  ui->endorseList->setModel(m_endorseDataModel);
-  ui->endorseList->setColumnHidden(0, true);
-  ui->endorseList->resizeColumnToContents(1);
-  ui->endorseList->resizeColumnToContents(2);
-  ui->endorseList->setItemDelegateForColumn(3, m_endorseComboBoxDelegate);
-  ui->endorseList->show();
-}
-
-void
-ContactPanel::updateDefaultIdentity(const QString& identity, const QString& nickName)
-{ 
-  // _LOG_DEBUG(identity.toStdString());
-  Name defaultIdentity(identity.toStdString());
-  Name defaultCertName = m_keyChain->createIdentity(defaultIdentity);
-
-  m_defaultIdentity = defaultIdentity;
-  m_profileEditor->setCurrentIdentity(m_defaultIdentity);
-  m_nickName = nickName.toStdString();
-  
-  m_face->unsetInterestFilter(m_invitationListenerId);
-  m_contactManager->setDefaultIdentity(m_defaultIdentity);
-  setInvitationListener();
-  collectEndorsement();
-}
-
-void
-ContactPanel::openProfileEditor()
-{ m_profileEditor->show(); }
-
-void
-ContactPanel::openAddContactPanel()
-{ m_addContactPanel->show(); }
-
-void
-ContactPanel::openBrowseContactDialog()
-{ 
-  m_browseContactDialog->show(); 
-  emit refreshCertDirectory();
-}
-
-void
-ContactPanel::removeContactButton()
-{
-  QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
-  QModelIndexList selectedList = selectionModel->selectedIndexes();
-  QModelIndexList::iterator it = selectedList.begin();
-  for(; it != selectedList.end(); it++)
-    {
-      string alias =  m_contactListModel->data(*it, Qt::DisplayRole).toString().toStdString();
-      vector<shared_ptr<ContactItem> >::iterator contactIt = m_contactList.begin();
-      for(; contactIt != m_contactList.end(); contactIt++)
-        {
-          if((*contactIt)->getAlias() == alias)
-            {
-              m_contactManager->getContactStorage()->removeContact((*contactIt)->getNameSpace());
-              m_contactList.erase(contactIt);
-              break;
-            }
-        }
-    }
-  refreshContactList();
-}
-
-void
-ContactPanel::addContactIntoValidator(const Name& contactNameSpace)
-{
-#ifdef WITH_SECURITY
-  shared_ptr<ContactItem> contact = m_contactManager->getContact(contactNameSpace);
-  if(static_cast<bool>(contact))
-    {
-      m_panelValidator->addTrustAnchor(contact->getSelfEndorseCertificate());
-      m_invitationValidator->addTrustAnchor(contact->getSelfEndorseCertificate());
-    }
-#endif
-}
-
-void
-ContactPanel::removeContactFromValidator(const Name& keyName)
-{ 
-#ifdef WITH_SECURITY
-  m_panelValidator->removeTrustAnchor(keyName);
-  m_invitationValidator->removeTrustAnchor(keyName);
-#endif
-}
-
-void
-ContactPanel::refreshContactList()
-{
-  m_contactList.clear();
-  m_contactManager->getContactItemList(m_contactList);
-  QStringList contactNameList;
-  for(int i = 0; i < m_contactList.size(); i++)
-    contactNameList << QString::fromStdString(m_contactList[i]->getAlias());
-
-  m_contactListModel->setStringList(contactNameList);
-}
-
-void
-ContactPanel::showContextMenu(const QPoint& pos)
-{
-  QMenu menu(ui->ContactList);
-  menu.addAction(m_menuAlias);
-  connect(m_menuAlias, SIGNAL(triggered()),
-          this, SLOT(openSetAliasDialog()));
-  menu.exec(ui->ContactList->mapToGlobal(pos));
-
-}
-
-void
-ContactPanel::openSetAliasDialog()
-{
-  m_setAliasDialog->setTargetIdentity(m_currentSelectedContact->getNameSpace().toUri());
-  m_setAliasDialog->show();
-}
-
-void
-ContactPanel::openSettingDialog()
-{
-  m_settingDialog->setIdentity(m_defaultIdentity.toUri(), m_nickName);
-  m_settingDialog->show();
-}
-
-void
-ContactPanel::openStartChatDialog()
-{
-  Name chatroom("/ndn/broadcast/chronos");
-  chatroom.append(string("chatroom-") + getRandomString());
-
-  m_startChatDialog->setChatroom(chatroom.toUri());
-  m_startChatDialog->show();
-}
-
-// For inviter
-void
-ContactPanel::startChatroom(const QString& chatroom)
-{
-  Name chatroomName(chatroom.toStdString());
-
-  ChatDialog* chatDialog = new ChatDialog(m_contactManager, m_face, chatroomName, m_localPrefix, m_defaultIdentity, m_nickName);
-  m_chatDialogs[chatroomName] = chatDialog;
-  connect(chatDialog, SIGNAL(closeChatDialog(const ndn::Name&)),
-          this, SLOT(removeChatDialog(const ndn::Name&)));
-  connect(chatDialog, SIGNAL(noNdnConnection(const QString&)),
-          this, SLOT(showError(const QString&)));
-  connect(chatDialog, SIGNAL(inivationRejection(const QString&)),
-          this, SLOT(showWarning(const QString&)));
-
-  chatDialog->show();
-}
-
-// For Invitee
-void
-ContactPanel::startChatroom2(const Name& invitationInterest)
-{
-  Invitation invitation(invitationInterest);
-  Name chatroomName("/ndn/broadcast/chronos");
-  chatroomName.append(invitation.getChatroom());
-
-  ChatDialog* chatDialog = new ChatDialog(m_contactManager, m_face, chatroomName, m_localPrefix, m_defaultIdentity, m_nickName);
-  connect(chatDialog, SIGNAL(closeChatDialog(const ndn::Name&)),
-          this, SLOT(removeChatDialog(const ndn::Name&)));
-  connect(chatDialog, SIGNAL(noNdnConnection(const QString&)),
-          this, SLOT(showError(const QString&)));
-  connect(chatDialog, SIGNAL(inivationRejection(const QString&)),
-          this, SLOT(showWarning(const QString&)));
-
-  Block signatureBlock = invitationInterest.get(-1).blockFromValue();
-  Block signatureInfo = invitationInterest.get(-2).blockFromValue();
-  Signature signature(signatureInfo, signatureBlock);
-  
-  SignatureSha256WithRsa sig(signature);
-  Name keyLocatorName = sig.getKeyLocator().getName();
-  Name inviter = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName).getPrefix(-1);
-
-#ifdef WITH_SECURITY
-  shared_ptr<IdentityCertificate> idCert = m_invitationValidator->getValidatedDskCertificate(keyLocatorName);
-  chatDialog->addChatDataRule(invitation.getInviterRoutingPrefix(), *idCert, true);
-  chatDialog->publishIntroCert(*idCert, true);
-  shared_ptr<ContactItem> inviterItem = m_contactManager->getContact(inviter);
-  chatDialog->addTrustAnchor(inviterItem->getSelfEndorseCertificate());
-#endif
-  
-  m_chatDialogs[chatroomName] = chatDialog;
-
-  chatDialog->show();
-}
-
-void
-ContactPanel::prepareInvitationReply(const Name& invitationInterest, const string& content)
-{
-  Invitation invitation(invitationInterest);
-
-  Name dataName = invitationInterest;
-  dataName.appendVersion();
-
-  Data data(dataName);
-  data.setContent(reinterpret_cast<const uint8_t*>(content.c_str()), content.size());
-  data.setFreshnessPeriod(1000);
-
-  m_keyChain->signByIdentity(data, invitation.getInviteeNameSpace());
-
-  m_face->put(data);
-}
-
-void
-ContactPanel::isIntroducerChanged(int state)
-{
-  if(state == Qt::Checked)
-    {
-      ui->addScope->setEnabled(true);
-      ui->deleteScope->setEnabled(true);
-      ui->trustScopeList->setEnabled(true);
-      
-      string filter("contact_namespace = '");
-      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
-
-      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-      m_trustScopeModel->setTable("TrustScope");
-      m_trustScopeModel->setFilter(filter.c_str());
-      m_trustScopeModel->select();
-      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
-      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
-      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
-
-      ui->trustScopeList->setModel(m_trustScopeModel);
-      ui->trustScopeList->setColumnHidden(0, true);
-      ui->trustScopeList->setColumnHidden(1, true);
-      ui->trustScopeList->show();
-
-      m_currentSelectedContact->setIsIntroducer(true);
-    }
-  else
-    {
-      ui->addScope->setEnabled(false);
-      ui->deleteScope->setEnabled(false);
-
-      string filter("contact_namespace = '");
-      filter.append(m_currentSelectedContact->getNameSpace().toUri()).append("'");
-
-      m_trustScopeModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-      m_trustScopeModel->setTable("TrustScope");
-      m_trustScopeModel->setFilter(filter.c_str());
-      m_trustScopeModel->select();
-      m_trustScopeModel->setHeaderData(0, Qt::Horizontal, QObject::tr("ID"));
-      m_trustScopeModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Contact"));
-      m_trustScopeModel->setHeaderData(2, Qt::Horizontal, QObject::tr("TrustScope"));
-
-      ui->trustScopeList->setModel(m_trustScopeModel);
-      ui->trustScopeList->setColumnHidden(0, true);
-      ui->trustScopeList->setColumnHidden(1, true);
-      ui->trustScopeList->show();
-
-      ui->trustScopeList->setEnabled(false);
-
-      m_currentSelectedContact->setIsIntroducer(false);
-    }
-  m_contactManager->getContactStorage()->updateIsIntroducer(m_currentSelectedContact->getNameSpace(), m_currentSelectedContact->isIntroducer());
-}
-
-void
-ContactPanel::addScopeClicked()
-{
-  int rowCount = m_trustScopeModel->rowCount();
-  QSqlRecord record;
-  QSqlField identityField("contact_namespace", QVariant::String);
-  record.append(identityField);
-  record.setValue("contact_namespace", QString::fromStdString(m_currentSelectedContact->getNameSpace().toUri()));
-  m_trustScopeModel->insertRow(rowCount);
-  m_trustScopeModel->setRecord(rowCount, record);
-}
-
-void
-ContactPanel::deleteScopeClicked()
-{
-  QItemSelectionModel* selectionModel = ui->trustScopeList->selectionModel();
-  QModelIndexList indexList = selectionModel->selectedIndexes();
-
-  int i = indexList.size() - 1;  
-  for(; i >= 0; i--)
-    m_trustScopeModel->removeRow(indexList[i].row());
-    
-  m_trustScopeModel->submitAll();
-}
-
-void
-ContactPanel::saveScopeClicked()
-{ m_trustScopeModel->submitAll(); }
-
-void
-ContactPanel::endorseButtonClicked()
-{
-  m_endorseDataModel->submitAll();
-  m_contactManager->updateEndorseCertificate(m_currentSelectedContact->getNameSpace(), m_defaultIdentity);
-}
-
-void
-ContactPanel::removeChatDialog(const ndn::Name& chatroomName)
-{
-  map<Name, ChatDialog*>::iterator it = m_chatDialogs.find(chatroomName);
-
-  ChatDialog* deletedChat = NULL;
-  if(it != m_chatDialogs.end())
-    {
-      deletedChat = it->second;
-      m_chatDialogs.erase(it);      
-    }
-  if (deletedChat != NULL)
-    delete deletedChat;
-}
-
-#if WAF
-#include "contactpanel.moc"
-#include "contactpanel.cpp.moc"
-#endif
diff --git a/src/contactpanel.h b/src/contactpanel.h
deleted file mode 100644
index 9e0c3b3..0000000
--- a/src/contactpanel.h
+++ /dev/null
@@ -1,285 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef CONTACTPANEL_H
-#define CONTACTPANEL_H
-
-#include <QDialog>
-#include <QStringListModel>
-#include <QtSql/QSqlDatabase>
-#include <QMenu>
-#include <QMessageBox>
-
-#include "profileeditor.h"
-#include "addcontactpanel.h"
-#include "setaliasdialog.h"
-#include "startchatdialog.h"
-#include "invitationdialog.h"
-#include "settingdialog.h"
-#include "chatdialog.h"
-#include "endorse-combobox-delegate.h"
-#include "browsecontactdialog.h"
-#include "warningdialog.h"
-
-#ifndef Q_MOC_RUN
-#include "contact-manager.h"
-#include "invitation.h"
-
-#ifdef WITH_SECURITY
-#include "validator-panel.h"
-#include "validator-invitation.h"
-#else
-#include <ndn-cpp-dev/security/validator-null.hpp>
-#endif
-
-#endif
-
-
-namespace Ui {
-class ContactPanel;
-}
-
-class ContactPanel : public QDialog
-{
-  Q_OBJECT
-
-public:
-  explicit ContactPanel(ndn::shared_ptr<ndn::Face> face,
-                        QWidget *parent = 0);
-
-  ~ContactPanel();
-
-private:  
-  void
-  createAction();
-
-  void
-  openDB();
-
-  void
-  loadTrustAnchor();
-
-  void
-  setLocalPrefix(int retry = 10);
-
-  void
-  onLocalPrefix(const ndn::Interest& interest, ndn::Data& data);
-  
-  void
-  onLocalPrefixTimeout(const ndn::Interest& interest, int retry);
-
-  void
-  setInvitationListener();
-
-  void
-  onInvitation(const ndn::Name& prefix, const ndn::Interest& interest);
-
-  void
-  onInvitationRegisterFailed(const ndn::Name& prefix, const std::string& msg);
-
-  inline void
-  onInvitationValidated(const ndn::shared_ptr<const ndn::Interest>& interest);
-  
-  inline void
-  onInvitationValidationFailed(const ndn::shared_ptr<const ndn::Interest>& interest);
-
-  void
-  popChatInvitation(const ndn::Name& interestName);
-
-  void
-  sendInterest(const ndn::Interest& interest,
-               const ndn::OnDataValidated& onValidated,
-               const ndn::OnDataValidationFailed& onValidationFailed,
-               const chronos::TimeoutNotify& timeoutNotify,
-               int retry = 1);
-
-  void
-  onTargetData(const ndn::Interest& interest, 
-               ndn::Data& data,
-               const ndn::OnDataValidated& onValidated,
-               const ndn::OnDataValidationFailed& onValidationFailed);
-
-  void
-  onTargetTimeout(const ndn::Interest& interest, 
-                  int retry,
-                  const ndn::OnDataValidated& onValidated,
-                  const ndn::OnDataValidationFailed& onValidationFailed,
-                  const chronos::TimeoutNotify& timeoutNotify);
-
-  void
-  collectEndorsement();
-
-  void
-  onDnsEndorseeValidated(const ndn::shared_ptr<const ndn::Data>& data, int count);
-
-  void
-  onDnsEndorseeValidationFailed(const ndn::shared_ptr<const ndn::Data>& data, int count);
-
-  void
-  onDnsEndorseeTimeoutNotify(int count);
-
-  void 
-  updateCollectStatus(int count);
-
-  std::string
-  getRandomString();
-
-signals:
-  void
-  refreshCertDirectory();
-
-private slots:
-  void
-  showError(const QString& msg);
-
-  void
-  showWarning(const QString& msg);
-
-  void
-  updateSelection(const QItemSelection &selected,
-                  const QItemSelection &deselected);
-
-  void
-  updateDefaultIdentity(const QString& identity,
-                        const QString& nickName);
-
-  void
-  openProfileEditor();
-
-  void
-  openAddContactPanel();
-  
-  void
-  openBrowseContactDialog();
-
-  void
-  openSetAliasDialog();
-
-  void
-  removeContactButton();
-  
-  void
-  openStartChatDialog();
-
-  void
-  openSettingDialog();
-
-  void
-  refreshContactList();
-
-  void
-  showContextMenu(const QPoint& pos);
-
-  void
-  startChatroom(const QString& chatroom);
-
-  void 
-  startChatroom2(const ndn::Name& invitationInterest);
-
-  inline void
-  acceptInvitation(const ndn::Name& invitationInterest);
-
-  inline void
-  rejectInvitation(const ndn::Name& invitationInterest);
-
-  void
-  prepareInvitationReply(const ndn::Name& invitationInterest, const std::string& content);
-
-  void
-  isIntroducerChanged(int state);
-
-  void
-  addScopeClicked();
-
-  void
-  deleteScopeClicked();
-
-  void
-  saveScopeClicked();
-
-  void
-  endorseButtonClicked();
-  
-  void
-  removeChatDialog(const ndn::Name& chatroomName);
-
-  void 
-  addContactIntoValidator(const ndn::Name& nameSpace);
-
-  void 
-  removeContactFromValidator(const ndn::Name& keyName);
-  
-
-private:
-
-  Ui::ContactPanel *ui;
-  WarningDialog* m_warningDialog;
-  QStringListModel* m_contactListModel;
-  ProfileEditor* m_profileEditor;
-  AddContactPanel* m_addContactPanel;
-  BrowseContactDialog* m_browseContactDialog;
-  SetAliasDialog* m_setAliasDialog;
-  StartChatDialog* m_startChatDialog;
-  InvitationDialog* m_invitationDialog;
-  SettingDialog* m_settingDialog;
-  std::map<ndn::Name, ChatDialog*> m_chatDialogs;
-  QAction* m_menuAlias;
-
-#ifdef WITH_SECURITY
-  ndn::shared_ptr<chronos::ValidatorPanel> m_panelValidator;
-  ndn::shared_ptr<chronos::ValidatorInvitation> m_invitationValidator;
-#else
-  ndn::shared_ptr<ndn::Validator> m_panelValidator;
-  ndn::shared_ptr<ndn::Validator> m_invitationValidator;
-#endif
-
-  ndn::shared_ptr<ndn::KeyChain> m_keyChain;
-  ndn::shared_ptr<ndn::Face> m_face;
-  ndn::shared_ptr<boost::asio::io_service> m_ioService;
-
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-
-  std::vector<ndn::shared_ptr<chronos::ContactItem> > m_contactList;
-  ndn::shared_ptr<std::vector<bool> > m_collectStatus;
-
-  const ndn::RegisteredPrefixId* m_invitationListenerId;
-
-  ndn::Name m_defaultIdentity;
-  std::string m_nickName;
-  ndn::Name m_localPrefix;
-  ndn::Name m_inviteListenPrefix;
-
-  ndn::shared_ptr<chronos::ContactItem> m_currentSelectedContact;
-  QSqlTableModel* m_trustScopeModel;
-  QSqlTableModel* m_endorseDataModel;
-  EndorseComboBoxDelegate* m_endorseComboBoxDelegate;
-};
-
-void
-ContactPanel::onInvitationValidated(const ndn::shared_ptr<const ndn::Interest>& interest)
-{ popChatInvitation(interest->getName()); }
-
-void
-ContactPanel::onInvitationValidationFailed(const ndn::shared_ptr<const ndn::Interest>& interest)
-{}
-
-void
-ContactPanel::acceptInvitation(const ndn::Name& invitationInterest)
-{ 
-  prepareInvitationReply(invitationInterest, m_localPrefix.toUri()); 
-  startChatroom2(invitationInterest);
-}
-
-void
-ContactPanel::rejectInvitation(const ndn::Name& invitationInterest)
-{ prepareInvitationReply(invitationInterest, "nack"); }
-
-
-#endif // CONTACTPANEL_H
diff --git a/src/contactpanel.ui b/src/contactpanel.ui
deleted file mode 100644
index 5410c2e..0000000
--- a/src/contactpanel.ui
+++ /dev/null
@@ -1,344 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ContactPanel</class>
- <widget class="QDialog" name="ContactPanel">
-  <property name="enabled">
-   <bool>true</bool>
-  </property>
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>600</width>
-    <height>480</height>
-   </rect>
-  </property>
-  <property name="sizePolicy">
-   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
-    <horstretch>0</horstretch>
-    <verstretch>0</verstretch>
-   </sizepolicy>
-  </property>
-  <property name="windowTitle">
-   <string>ChronoChat Contacts</string>
-  </property>
-  <widget class="QWidget" name="layoutWidget">
-   <property name="geometry">
-    <rect>
-     <x>12</x>
-     <y>12</y>
-     <width>581</width>
-     <height>471</height>
-    </rect>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout_2" stretch="30,1">
-    <item>
-     <layout class="QHBoxLayout" name="ContactPanelLayout" stretch="3,7">
-      <property name="spacing">
-       <number>10</number>
-      </property>
-      <property name="sizeConstraint">
-       <enum>QLayout::SetDefaultConstraint</enum>
-      </property>
-      <item>
-       <widget class="QListView" name="ContactList">
-        <property name="contextMenuPolicy">
-         <enum>Qt::CustomContextMenu</enum>
-        </property>
-        <property name="acceptDrops">
-         <bool>false</bool>
-        </property>
-        <property name="editTriggers">
-         <set>QAbstractItemView::NoEditTriggers</set>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QTabWidget" name="ContactInfo">
-        <property name="currentIndex">
-         <number>0</number>
-        </property>
-        <widget class="QWidget" name="General">
-         <attribute name="title">
-          <string>General</string>
-         </attribute>
-         <widget class="QGraphicsView" name="Avatar">
-          <property name="geometry">
-           <rect>
-            <x>130</x>
-            <y>10</y>
-            <width>128</width>
-            <height>128</height>
-           </rect>
-          </property>
-         </widget>
-         <widget class="QWidget" name="layoutWidget">
-          <property name="geometry">
-           <rect>
-            <x>30</x>
-            <y>160</y>
-            <width>331</width>
-            <height>124</height>
-           </rect>
-          </property>
-          <layout class="QVBoxLayout" name="verticalLayout">
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayout" stretch="35,100">
-             <property name="spacing">
-              <number>-1</number>
-             </property>
-             <item>
-              <widget class="QLabel" name="NameSpaceLabel">
-               <property name="font">
-                <font>
-                 <weight>75</weight>
-                 <bold>true</bold>
-                </font>
-               </property>
-               <property name="text">
-                <string>Name space</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLineEdit" name="NameSpaceData">
-               <property name="font">
-                <font>
-                 <family>Lucida Grande</family>
-                </font>
-               </property>
-               <property name="readOnly">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="35,100">
-             <item>
-              <widget class="QLabel" name="NameLabel">
-               <property name="font">
-                <font>
-                 <weight>75</weight>
-                 <bold>true</bold>
-                </font>
-               </property>
-               <property name="text">
-                <string>Name</string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLineEdit" name="NameData">
-               <property name="font">
-                <font>
-                 <family>Lucida Grande</family>
-                </font>
-               </property>
-               <property name="readOnly">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="35,100">
-             <item>
-              <widget class="QLabel" name="InstitutionLabel">
-               <property name="font">
-                <font>
-                 <weight>75</weight>
-                 <bold>true</bold>
-                </font>
-               </property>
-               <property name="text">
-                <string>Institution   </string>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QLineEdit" name="InstitutionData">
-               <property name="font">
-                <font>
-                 <family>Lucida Grande</family>
-                </font>
-               </property>
-               <property name="readOnly">
-                <bool>true</bool>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-          </layout>
-         </widget>
-        </widget>
-        <widget class="QWidget" name="TrustScope">
-         <attribute name="title">
-          <string>Trust Scope</string>
-         </attribute>
-         <widget class="QWidget" name="layoutWidget">
-          <property name="geometry">
-           <rect>
-            <x>20</x>
-            <y>10</y>
-            <width>362</width>
-            <height>371</height>
-           </rect>
-          </property>
-          <layout class="QVBoxLayout" name="verticalLayout_3">
-           <item>
-            <widget class="QCheckBox" name="isIntroducer">
-             <property name="text">
-              <string>Set as introducer</string>
-             </property>
-            </widget>
-           </item>
-           <item>
-            <widget class="QTableView" name="trustScopeList">
-             <attribute name="horizontalHeaderStretchLastSection">
-              <bool>true</bool>
-             </attribute>
-            </widget>
-           </item>
-           <item>
-            <layout class="QHBoxLayout" name="horizontalLayout_4">
-             <item>
-              <widget class="QPushButton" name="addScope">
-               <property name="text">
-                <string>Add Scope</string>
-               </property>
-               <property name="autoDefault">
-                <bool>false</bool>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QPushButton" name="deleteScope">
-               <property name="text">
-                <string>Delete Scope</string>
-               </property>
-               <property name="autoDefault">
-                <bool>false</bool>
-               </property>
-              </widget>
-             </item>
-             <item>
-              <widget class="QPushButton" name="saveButton">
-               <property name="text">
-                <string>Save</string>
-               </property>
-               <property name="autoDefault">
-                <bool>false</bool>
-               </property>
-              </widget>
-             </item>
-            </layout>
-           </item>
-          </layout>
-         </widget>
-        </widget>
-        <widget class="QWidget" name="Endorse">
-         <attribute name="title">
-          <string>Endorse</string>
-         </attribute>
-         <widget class="QTableView" name="endorseList">
-          <property name="geometry">
-           <rect>
-            <x>20</x>
-            <y>10</y>
-            <width>351</width>
-            <height>331</height>
-           </rect>
-          </property>
-          <attribute name="horizontalHeaderStretchLastSection">
-           <bool>true</bool>
-          </attribute>
-         </widget>
-         <widget class="QPushButton" name="endorseButton">
-          <property name="geometry">
-           <rect>
-            <x>260</x>
-            <y>350</y>
-            <width>114</width>
-            <height>32</height>
-           </rect>
-          </property>
-          <property name="text">
-           <string>Endorse</string>
-          </property>
-          <property name="autoDefault">
-           <bool>false</bool>
-          </property>
-         </widget>
-        </widget>
-       </widget>
-      </item>
-     </layout>
-    </item>
-    <item>
-     <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="4,3,3,3">
-      <item>
-       <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,1">
-        <property name="spacing">
-         <number>-1</number>
-        </property>
-        <item>
-         <widget class="QPushButton" name="AddContactButton">
-          <property name="text">
-           <string>Add </string>
-          </property>
-          <property name="autoDefault">
-           <bool>false</bool>
-          </property>
-         </widget>
-        </item>
-        <item>
-         <widget class="QPushButton" name="DeleteContactButton">
-          <property name="text">
-           <string>Delete</string>
-          </property>
-          <property name="autoDefault">
-           <bool>false</bool>
-          </property>
-         </widget>
-        </item>
-       </layout>
-      </item>
-      <item>
-       <widget class="QPushButton" name="chatButton">
-        <property name="text">
-         <string>Chat!</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="settingButton">
-        <property name="text">
-         <string>Setting</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="EditProfileButton">
-        <property name="text">
-         <string>Edit Profile</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/controller.cpp b/src/controller.cpp
new file mode 100644
index 0000000..723617a
--- /dev/null
+++ b/src/controller.cpp
@@ -0,0 +1,803 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include <QApplication>
+#include <QMessageBox>
+#include <QDir>
+#include <QTimer>
+#include "controller.h"
+
+#ifndef Q_MOC_RUN
+#include <boost/filesystem.hpp>
+#include <boost/lexical_cast.hpp>
+#include <ndn-cpp-dev/util/random.hpp>
+#include <cryptopp/sha.h>
+#include <cryptopp/hex.h>
+#include <cryptopp/files.h>
+#include <cryptopp/filters.h>
+#include "config.pb.h"
+#include "endorse-info.pb.h"
+#include "logging.h"
+#endif
+
+INIT_LOGGER("chronos.Controller");
+
+using namespace ndn;
+
+Q_DECLARE_METATYPE(ndn::Name)
+Q_DECLARE_METATYPE(ndn::IdentityCertificate)
+Q_DECLARE_METATYPE(chronos::EndorseInfo)
+
+namespace chronos {
+
+static const uint8_t ROUTING_PREFIX_SEPARATOR[2] = {0xF0, 0x2E};
+
+// constructor & destructor
+Controller::Controller(shared_ptr<Face> face,
+		       QWidget* parent)
+  : QDialog(parent)
+  , m_face(face)
+  , m_invitationListenerId(0)
+  , m_contactManager(m_face)
+  , m_settingDialog(new SettingDialog)
+  , m_startChatDialog(new StartChatDialog)
+  , m_profileEditor(new ProfileEditor)
+  , m_invitationDialog(new InvitationDialog)
+  , m_contactPanel(new ContactPanel)
+  , m_browseContactDialog(new BrowseContactDialog)
+  , m_addContactPanel(new AddContactPanel)
+{
+  qRegisterMetaType<ndn::Name>("ndn.Name");
+  qRegisterMetaType<ndn::IdentityCertificate>("ndn.IdentityCertificate");
+  qRegisterMetaType<chronos::EndorseInfo>("chronos.EndorseInfo");
+
+  connect(this, SIGNAL(localPrefixUpdated(const QString&)),
+          this, SLOT(onLocalPrefixUpdated(const QString&)));
+
+  // Connection to ContactManager
+  connect(this, SIGNAL(identityUpdated(const QString&)),
+          &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
+  connect(&m_contactManager, SIGNAL(warning(const QString&)),
+          this, SLOT(onWarning(const QString&)));
+  connect(this, SIGNAL(refreshBrowseContact()),
+          &m_contactManager, SLOT(onRefreshBrowseContact()));
+  connect(&m_contactManager, SIGNAL(contactInfoFetchFailed(const QString&)),
+          this, SLOT(onWarning(const QString&)));
+  connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
+          this, SLOT(onContactIdListReady(const QStringList&)));
+
+  // Connection to SettingDialog
+  connect(this, SIGNAL(identityUpdated(const QString&)),
+          m_settingDialog, SLOT(onIdentityUpdated(const QString&)));
+  connect(m_settingDialog, SIGNAL(identityUpdated(const QString&)),
+          this, SLOT(onIdentityUpdated(const QString&)));
+  connect(m_settingDialog, SIGNAL(nickUpdated(const QString&)),
+          this, SLOT(onNickUpdated(const QString&)));
+
+  // Connection to ProfileEditor
+  connect(this, SIGNAL(closeDBModule()),
+          m_profileEditor, SLOT(onCloseDBModule()));
+  connect(this, SIGNAL(identityUpdated(const QString&)),
+          m_profileEditor, SLOT(onIdentityUpdated(const QString&)));
+  connect(m_profileEditor, SIGNAL(updateProfile()),
+          &m_contactManager, SLOT(onUpdateProfile()));
+
+  // Connection to StartChatDialog
+  connect(m_startChatDialog, SIGNAL(startChatroom(const QString&, bool)),
+          this, SLOT(onStartChatroom(const QString&, bool)));
+
+  // Connection to InvitationDialog
+  connect(m_invitationDialog, SIGNAL(invitationResponded(const ndn::Name&, bool)),
+          this, SLOT(onInvitationResponded(const ndn::Name&, bool)));
+
+  // Connection to AddContactPanel
+  connect(m_addContactPanel, SIGNAL(fetchInfo(const QString&)),
+          &m_contactManager, SLOT(onFetchContactInfo(const QString&)));
+  connect(m_addContactPanel, SIGNAL(addContact(const QString&)),
+          &m_contactManager, SLOT(onAddFetchedContact(const QString&)));
+  connect(&m_contactManager, SIGNAL(contactEndorseInfoReady(const chronos::EndorseInfo&)),
+          m_addContactPanel, SLOT(onContactEndorseInfoReady(const chronos::EndorseInfo&)));
+
+
+  // Connection to BrowseContactDialog
+  connect(m_browseContactDialog, SIGNAL(directAddClicked()),
+          this, SLOT(onDirectAdd()));
+  connect(m_browseContactDialog, SIGNAL(fetchIdCert(const QString&)),
+          &m_contactManager, SLOT(onFetchIdCert(const QString&)));
+  connect(m_browseContactDialog, SIGNAL(addContact(const QString&)),
+          &m_contactManager, SLOT(onAddFetchedContactIdCert(const QString&)));
+  connect(&m_contactManager, SIGNAL(idCertNameListReady(const QStringList&)),
+          m_browseContactDialog, SLOT(onIdCertNameListReady(const QStringList&)));
+  connect(&m_contactManager, SIGNAL(nameListReady(const QStringList&)),
+          m_browseContactDialog, SLOT(onNameListReady(const QStringList&)));
+  connect(&m_contactManager, SIGNAL(idCertReady(const ndn::IdentityCertificate&)),
+          m_browseContactDialog, SLOT(onIdCertReady(const ndn::IdentityCertificate&)));
+
+  // Connection to ContactPanel
+  connect(m_contactPanel, SIGNAL(waitForContactList()),
+          &m_contactManager, SLOT(onWaitForContactList()));
+  connect(m_contactPanel, SIGNAL(waitForContactInfo(const QString&)),
+          &m_contactManager, SLOT(onWaitForContactInfo(const QString&)));
+  connect(m_contactPanel, SIGNAL(removeContact(const QString&)),
+          &m_contactManager, SLOT(onRemoveContact(const QString&)));
+  connect(m_contactPanel, SIGNAL(updateAlias(const QString&, const QString&)),
+          &m_contactManager, SLOT(onUpdateAlias(const QString&, const QString&)));
+  connect(m_contactPanel, SIGNAL(updateIsIntroducer(const QString&, bool)),
+          &m_contactManager, SLOT(onUpdateIsIntroducer(const QString&, bool)));
+  connect(m_contactPanel, SIGNAL(updateEndorseCertificate(const QString&)),
+          &m_contactManager, SLOT(onUpdateEndorseCertificate(const QString&)));
+  connect(m_contactPanel, SIGNAL(warning(const QString&)),
+          this, SLOT(onWarning(const QString&)));
+  connect(this, SIGNAL(closeDBModule()),
+          m_contactPanel, SLOT(onCloseDBModule()));
+  connect(this, SIGNAL(identityUpdated(const QString&)),
+          m_contactPanel, SLOT(onIdentityUpdated(const QString&)));
+  connect(&m_contactManager, SIGNAL(contactAliasListReady(const QStringList&)),
+          m_contactPanel, SLOT(onContactAliasListReady(const QStringList&)));
+  connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
+          m_contactPanel, SLOT(onContactIdListReady(const QStringList&)));
+  connect(&m_contactManager, SIGNAL(contactInfoReady(const QString&, const QString&, const QString&, bool)),
+          m_contactPanel, SLOT(onContactInfoReady(const QString&, const QString&, const QString&, bool)));
+
+  initialize();
+
+  createTrayIcon();          
+}
+  
+Controller::~Controller()
+{
+  saveConf();
+}
+
+// public methods
+
+
+// private methods
+std::string
+Controller::getDBName()
+{
+  std::string dbName("chronos-");
+
+  std::stringstream ss;
+  {
+    using namespace CryptoPP;
+
+    SHA256 hash;
+    StringSource(m_identity.wireEncode().wire(), m_identity.wireEncode().size(), true,
+                 new HashFilter(hash, new HexEncoder(new FileSink(ss), false)));
+  }
+  dbName.append(ss.str()).append(".db");
+
+  return dbName;
+}
+
+void
+Controller::openDB()
+{
+  m_db = QSqlDatabase::addDatabase("QSQLITE");
+  QString path = (QDir::home().path());
+  path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append(getDBName().c_str());
+  m_db.setDatabaseName(path);
+  bool ok = m_db.open();
+
+  _LOG_DEBUG("DB opened: " << std::boolalpha << ok );
+}
+
+void
+Controller::initialize()
+{
+  loadConf();
+  
+  m_keyChain.createIdentity(m_identity);
+
+  openDB();
+
+  emit identityUpdated(QString(m_identity.toUri().c_str()));
+
+  setInvitationListener();
+}
+
+void
+Controller::setInvitationListener()
+{
+  if(m_invitationListenerId != 0)
+    m_face->unsetInterestFilter(m_invitationListenerId);
+  
+  Name invitationPrefix;
+  Name routingPrefix = getInvitationRoutingPrefix();
+  size_t offset = 0;
+  if(!routingPrefix.isPrefixOf(m_identity))
+    {
+      invitationPrefix.append(routingPrefix).append(ROUTING_PREFIX_SEPARATOR, 2);
+      offset = routingPrefix.size() + 1;
+    }
+  invitationPrefix.append(m_identity).append("CHRONOCHAT-INVITATION");
+
+  m_invitationListenerId = m_face->setInterestFilter(invitationPrefix, 
+                                                     bind(&Controller::onInvitationInterest, this, _1, _2, offset),
+                                                     bind(&Controller::onInvitationRegisterFailed, this, _1, _2));
+}
+
+void
+Controller::loadConf()
+{
+  namespace fs = boost::filesystem;
+
+  fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
+  fs::create_directories (chronosDir);
+
+  std::ifstream is((chronosDir / "config").c_str ());
+  ChronoChat::Conf conf;
+  if(conf.ParseFromIstream(&is))
+    {
+      m_identity.clear();
+      m_identity.append(conf.identity());
+      if(conf.has_nick())
+        m_nick = conf.nick();
+      else
+        m_nick = m_identity.get(-1).toUri();
+    }
+  else
+    {
+      m_identity.clear();
+      // TODO: change below to system default;
+      m_identity.append("chronochat-tmp-identity")
+        .append(boost::lexical_cast<std::string>(random::generateWord64()));
+      
+      m_nick = m_identity.get(-1).toUri();
+    }
+}
+
+void 
+Controller::saveConf()
+{
+  namespace fs = boost::filesystem;
+
+  fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
+  fs::create_directories (chronosDir);
+
+  std::ofstream os((chronosDir / "config").c_str ());
+  ChronoChat::Conf conf;
+  conf.set_identity(m_identity.toUri());
+  if(!m_nick.empty())
+    conf.set_nick(m_nick);
+  conf.SerializeToOstream(&os);
+
+  os.close();
+}
+
+void
+Controller::createActions()
+{
+  m_startChatroom = new QAction(tr("Start new chat"), this);
+  connect(m_startChatroom, SIGNAL(triggered()), this, SLOT(onStartChatAction()));
+
+  m_settingsAction = new QAction(tr("Settings"), this);
+  connect(m_settingsAction, SIGNAL(triggered()), this, SLOT(onSettingsAction()));
+
+  m_editProfileAction = new QAction(tr("Edit profile"), this);
+  connect(m_editProfileAction, SIGNAL(triggered()), this, SLOT(onProfileEditorAction()));
+
+  m_contactListAction = new QAction(tr("Contact List"), this);
+  connect(m_contactListAction, SIGNAL(triggered()), this, SLOT(onContactListAction()));
+
+  m_addContactAction = new QAction(tr("Add contact"), this);
+  connect(m_addContactAction, SIGNAL(triggered()), this, SLOT(onAddContactAction()));
+
+  m_updateLocalPrefixAction = new QAction(tr("Update local prefix"), this);
+  connect(m_updateLocalPrefixAction, SIGNAL(triggered()), this, SLOT(onUpdateLocalPrefixAction()));
+
+  m_minimizeAction = new QAction(tr("Mi&nimize"), this);
+  connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(onMinimizeAction()));
+
+  m_quitAction = new QAction(tr("Quit"), this);
+  connect(m_quitAction, SIGNAL(triggered()), this, SLOT(onQuitAction()));
+}
+
+void
+Controller::createTrayIcon()
+{
+  createActions();
+
+  m_trayIconMenu = new QMenu(this);
+  m_trayIconMenu->addAction(m_startChatroom);
+  m_trayIconMenu->addSeparator();
+  m_trayIconMenu->addAction(m_settingsAction);
+  m_trayIconMenu->addAction(m_editProfileAction);
+  m_trayIconMenu->addSeparator();
+  m_trayIconMenu->addAction(m_contactListAction);
+  m_trayIconMenu->addAction(m_addContactAction);
+  m_trayIconMenu->addSeparator();
+  m_trayIconMenu->addAction(m_updateLocalPrefixAction);
+  m_trayIconMenu->addSeparator();
+  m_trayIconMenu->addAction(m_minimizeAction);
+  m_closeMenu = m_trayIconMenu->addMenu("Close chatroom");
+  m_closeMenu->setEnabled(false);
+  m_trayIconMenu->addSeparator();
+  m_trayIconMenu->addAction(m_quitAction);
+
+  m_trayIcon = new QSystemTrayIcon(this);
+  m_trayIcon->setContextMenu(m_trayIconMenu);
+
+  m_trayIcon->setIcon(QIcon(":/images/icon_small.png"));
+  m_trayIcon->setToolTip("ChronoChat System Tray Icon");
+  m_trayIcon->setVisible(true);
+}
+
+void
+Controller::updateMenu()
+{
+  QMenu* menu = new QMenu(this);
+  QMenu* closeMenu = 0;
+  
+  menu->addAction(m_startChatroom);
+  menu->addSeparator();
+  menu->addAction(m_settingsAction);
+  menu->addAction(m_editProfileAction);
+  menu->addSeparator();
+  menu->addAction(m_addContactAction);
+  menu->addSeparator();
+  {
+    ChatActionList::const_iterator it = m_chatActionList.begin();
+    ChatActionList::const_iterator end = m_chatActionList.end();
+    if(it != end)
+      {
+        for(; it != end; it++)
+          menu->addAction(it->second);
+        menu->addSeparator();
+      }
+  }
+  menu->addAction(m_updateLocalPrefixAction);
+  menu->addSeparator();
+  menu->addAction(m_minimizeAction);
+  closeMenu = menu->addMenu("Close chatroom");
+  {
+    ChatActionList::const_iterator it = m_closeActionList.begin();
+    ChatActionList::const_iterator end = m_closeActionList.end();
+    if(it == end)
+      {
+        closeMenu->setEnabled(false);
+      }
+    else
+      {
+        for(; it != end; it++)
+          closeMenu->addAction(it->second);
+      }
+  }
+  menu->addSeparator();
+  menu->addAction(m_quitAction);
+  
+  m_trayIcon->setContextMenu(menu);
+  delete m_trayIconMenu;
+  m_trayIconMenu = menu;
+  m_closeMenu = closeMenu;
+}
+
+void
+Controller::onLocalPrefix(const Interest& interest, Data& data)
+{
+  QString localPrefixStr = QString::fromUtf8
+    (reinterpret_cast<const char*>(data.getContent().value()), data.getContent().value_size())
+    .trimmed();
+
+  Name localPrefix(localPrefixStr.toStdString());
+  if(m_localPrefix.empty() || m_localPrefix != localPrefix)
+    emit localPrefixUpdated(localPrefixStr);
+}
+
+void
+Controller::onLocalPrefixTimeout(const Interest& interest)
+{
+  QString localPrefixStr("/private/local");
+
+  Name localPrefix(localPrefixStr.toStdString());
+  if(m_localPrefix.empty() || m_localPrefix != localPrefix)
+    emit localPrefixUpdated(localPrefixStr);
+}
+
+void
+Controller::onInvitationInterest(const Name& prefix, const Interest& interest, size_t routingPrefixOffset)
+{
+  shared_ptr<Interest> invitationInterest = make_shared<Interest>(boost::cref(interest.getName().getSubName(routingPrefixOffset)));
+
+  // check if the chatroom already exists;
+  try
+    {
+      Invitation invitation(invitationInterest->getName());
+      if(m_chatDialogList.find(invitation.getChatroom()) != m_chatDialogList.end())
+        return;
+    }
+  catch(Invitation::Error& e)
+    {
+      // Cannot parse the invitation;
+      return;
+    }
+
+  OnInterestValidated onValidated = bind(&Controller::onInvitationValidated, this, _1);
+  OnInterestValidationFailed onValidationFailed = bind(&Controller::onInvitationValidationFailed, this, _1, _2);
+  m_validator.validate(*invitationInterest, onValidated, onValidationFailed);
+}
+
+void
+Controller::onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo)
+{
+  std::cerr << "Controller::onInvitationRegisterFailed: " << failInfo << std::endl;
+}
+
+void
+Controller::onInvitationValidated(const shared_ptr<const Interest>& interest)
+{
+  Invitation invitation(interest->getName());
+  std::string alias = invitation.getInviterCertificate().getPublicKeyName().getPrefix(-1).toUri(); // Should be obtained via a method of ContactManager.
+
+  m_invitationDialog->setInvitation(alias, invitation.getChatroom(), interest->getName());
+  m_invitationDialog->show();
+}
+
+void
+Controller::onInvitationValidationFailed(const shared_ptr<const Interest>& interest, std::string failureInfo)
+{
+  std::cerr << "Invitation: " << interest->getName() << " cannot not be validated due to: " << failureInfo << std::endl;
+}
+
+std::string
+Controller::getRandomString()
+{
+  uint32_t r = random::generateWord32();
+  std::stringstream ss;
+  {
+    using namespace CryptoPP;
+    StringSource(reinterpret_cast<uint8_t*>(&r), 4, true,
+                 new HexEncoder(new FileSink(ss), false));
+    
+  }
+  // for(int i = 0; i < 8; i++)
+  //   {
+  //     uint32_t t = r & mask;
+  //     if(t < 10)
+  //       ss << static_cast<char>(t + 0x30);
+  //     else
+  //       ss << static_cast<char>(t + 0x57);
+  //     r = r >> 4;
+  //   }
+
+  return ss.str();
+}
+
+ndn::Name
+Controller::getInvitationRoutingPrefix()
+{
+  return Name("/ndn/broadcast");
+}
+
+void
+Controller::addChatDialog(const QString& chatroomName, ChatDialog* chatDialog)
+{
+  m_chatDialogList[chatroomName.toStdString()] = chatDialog;
+  connect(chatDialog, SIGNAL(closeChatDialog(const QString&)),
+          this, SLOT(onRemoveChatDialog(const QString&)));
+  connect(chatDialog, SIGNAL(showChatMessage(const QString&, const QString&, const QString&)),
+          this, SLOT(onShowChatMessage(const QString&, const QString&, const QString&)));
+  connect(this, SIGNAL(localPrefixUpdated(const QString&)),
+          chatDialog, SLOT(onLocalPrefixUpdated(const QString&)));
+
+  QAction* chatAction = new QAction(chatroomName, this);
+  m_chatActionList[chatroomName.toStdString()] = chatAction;
+  connect(chatAction, SIGNAL(triggered()), chatDialog, SLOT(showNormal()));
+
+  QAction* closeAction = new QAction(chatroomName, this);
+  m_closeActionList[chatroomName.toStdString()] = closeAction;
+  connect(closeAction, SIGNAL(triggered()), chatDialog, SLOT(onClose()));
+
+  updateMenu();
+}
+
+// private slots:
+void
+Controller::onIdentityUpdated(const QString& identity)
+{
+  Name identityName(identity.toStdString());
+
+  while(!m_chatDialogList.empty())
+    {
+      ChatDialogList::const_iterator it = m_chatDialogList.begin();
+      onRemoveChatDialog(QString::fromStdString(it->first));
+    }
+
+  m_identity = identityName;
+  m_keyChain.createIdentity(m_identity);
+
+  emit closeDBModule();
+  
+  QTimer::singleShot(500, this, SLOT(onIdentityUpdatedContinued()));
+
+}
+
+void
+Controller::onIdentityUpdatedContinued()
+{
+  QString connection = m_db.connectionName();
+  // _LOG_DEBUG("connection name: " << connection.toStdString());
+  QSqlDatabase::removeDatabase(connection);
+  m_db.close();
+  
+  openDB();
+
+  emit identityUpdated(QString(m_identity.toUri().c_str()));
+}
+
+void
+Controller::onContactIdListReady(const QStringList& list)
+{
+  ContactList contactList;
+
+  m_contactManager.getContactList(contactList);
+  m_validator.cleanTrustAnchor();
+
+  ContactList::const_iterator it  = contactList.begin();
+  ContactList::const_iterator end = contactList.end();
+
+  for(; it != end; it++)
+    m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
+
+}
+
+void
+Controller::onNickUpdated(const QString& nick)
+{
+  m_nick = nick.toStdString();
+}
+
+void
+Controller::onLocalPrefixUpdated(const QString& localPrefix)
+{
+  m_localPrefix = Name(localPrefix.toStdString());
+}
+
+void
+Controller::onStartChatAction()
+{
+  std::string chatroom = "chatroom-" + getRandomString();
+
+  m_startChatDialog->setChatroom(chatroom);
+  m_startChatDialog->show();
+  m_startChatDialog->raise();
+}
+
+void
+Controller::onSettingsAction()
+{
+  m_settingDialog->setNick(QString(m_nick.c_str()));
+  m_settingDialog->show();
+  m_settingDialog->raise();
+}
+
+void
+Controller::onProfileEditorAction()
+{
+  m_profileEditor->show();
+  m_profileEditor->raise();
+}
+
+void
+Controller::onAddContactAction()
+{
+  emit refreshBrowseContact();
+  m_browseContactDialog->show();
+  m_browseContactDialog->raise();
+}
+
+void
+Controller::onContactListAction()
+{
+  m_contactPanel->show();
+  m_contactPanel->raise();
+}
+
+void
+Controller::onDirectAdd()
+{
+  m_addContactPanel->show();
+  m_addContactPanel->raise();
+}
+
+void
+Controller::onUpdateLocalPrefixAction()
+{
+  // Name interestName();
+  Interest interest("/local/ndn/prefix");
+  interest.setInterestLifetime(1000);
+  interest.setMustBeFresh(true);
+
+  m_face->expressInterest(interest, 
+                          bind(&Controller::onLocalPrefix, this, _1, _2), 
+                          bind(&Controller::onLocalPrefixTimeout, this, _1));  
+}
+
+void
+Controller::onMinimizeAction()
+{
+  m_settingDialog->hide();
+  m_startChatDialog->hide();
+  m_profileEditor->hide();
+  m_invitationDialog->hide();
+  m_addContactPanel->hide();
+
+  ChatDialogList::iterator it = m_chatDialogList.begin();
+  ChatDialogList::iterator end = m_chatDialogList.end();
+  for(; it != end; it++)
+    it->second->hide();
+}
+
+void
+Controller::onQuitAction()
+{
+  while(!m_chatDialogList.empty())
+    {
+      ChatDialogList::const_iterator it = m_chatDialogList.begin();
+      onRemoveChatDialog(QString::fromStdString(it->first));
+    }
+
+  delete m_settingDialog;
+  delete m_startChatDialog;
+  delete m_profileEditor;
+  delete m_invitationDialog;
+  delete m_addContactPanel;
+  // TODO: clean up all the dialog.
+
+  QApplication::quit();
+}
+
+void
+Controller::onStartChatroom(const QString& chatroomName, bool secured)
+{
+  Name chatroomPrefix;
+  chatroomPrefix.append("ndn")
+    .append("broadcast")
+    .append("ChronoChat")
+    .append(chatroomName.toStdString());
+
+  // check if the chatroom exists
+  if(m_chatDialogList.find(chatroomName.toStdString()) != m_chatDialogList.end())
+    {
+      QMessageBox::information(this, tr("ChronoChat"),
+                               tr("You are creating an existing chatroom."
+                                  "You can check it in the context memu."));
+      return;
+    }
+
+  // TODO: We should create a chatroom specific key/cert (which should be created in the first half of this method, but let's use the default one for now.
+  shared_ptr<IdentityCertificate> idCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
+  ChatDialog* chatDialog = new ChatDialog(&m_contactManager, m_face, *idCert, chatroomPrefix, m_localPrefix, m_nick, secured);
+
+  addChatDialog(chatroomName, chatDialog);  
+  chatDialog->show();
+}
+
+void
+Controller::onInvitationResponded(const Name& invitationName, bool accepted)
+{
+  Data response;
+  shared_ptr<IdentityCertificate> chatroomCert;
+
+  // generate reply;
+  if(accepted)
+    {
+      Name responseName = invitationName;
+      responseName.append(m_localPrefix.wireEncode());
+
+      response.setName(responseName);
+
+      // We should create a particular certificate for this chatroom, but let's use default one for now.
+      chatroomCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
+
+      response.setContent(chatroomCert->wireEncode());
+      response.setFreshnessPeriod(1000);      
+    }
+  else
+    {
+      response.setName(invitationName);
+      response.setFreshnessPeriod(1000);
+    }
+  
+  // Check if we need a wrapper
+  Name invitationRoutingPrefix = getInvitationRoutingPrefix();
+  if(invitationRoutingPrefix.isPrefixOf(m_identity))
+    {
+      m_keyChain.signByIdentity(response, m_identity);
+      m_face->put(response);
+    }
+  else
+    {
+      Name wrappedName;
+      wrappedName.append(invitationRoutingPrefix).append(ROUTING_PREFIX_SEPARATOR, 2);
+      
+      Data wrappedData(wrappedName);
+      wrappedData.setContent(response.wireEncode());
+      wrappedData.setFreshnessPeriod(1000);
+
+      m_keyChain.signByIdentity(response, m_identity);
+      m_face->put(response);
+    }
+
+  // create chatroom
+  if(accepted)
+    {
+      Invitation invitation(invitationName);
+      Name chatroomPrefix;
+      chatroomPrefix.append("ndn")
+        .append("broadcast")
+        .append("ChronoChat")
+        .append(invitation.getChatroom());
+
+      //We should create a chatroom specific key/cert (which should be created in the first half of this method, but let's use the default one for now.
+      shared_ptr<IdentityCertificate> idCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
+      ChatDialog* chatDialog = new ChatDialog(&m_contactManager, m_face, *idCert, chatroomPrefix, m_localPrefix, m_nick, true);
+
+      addChatDialog(QString::fromStdString(invitation.getChatroom()), chatDialog);
+      chatDialog->addSyncAnchor(invitation);
+      chatDialog->show();
+    }
+}
+
+void
+Controller::onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data)
+{
+  m_trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(chatroomName), 
+                          QString("<%1>: %2").arg(from).arg(data), 
+                          QSystemTrayIcon::Information, 20000);
+  m_trayIcon->setIcon(QIcon(":/images/note.png"));
+}
+
+void
+Controller::onRemoveChatDialog(const QString& chatroomName)
+{
+  ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
+
+  if(it != m_chatDialogList.end())
+    {
+      ChatDialog* deletedChat = it->second;
+      if(deletedChat)
+        delete deletedChat;
+      m_chatDialogList.erase(it);
+
+      QAction* chatAction = m_chatActionList[chatroomName.toStdString()];
+      QAction* closeAction = m_closeActionList[chatroomName.toStdString()];
+      if(chatAction)
+        delete chatAction;
+      if(closeAction)
+        delete closeAction;
+      
+      m_chatActionList.erase(chatroomName.toStdString());
+      m_closeActionList.erase(chatroomName.toStdString());
+      
+      updateMenu();
+    }
+}
+
+void
+Controller::onWarning(const QString& msg)
+{
+  QMessageBox::information(this, tr("ChronoChat"), msg);
+}
+
+void
+Controller::onError(const QString& msg) 
+{
+  QMessageBox::critical(this, tr("ChronoChat"), msg, QMessageBox::Ok);
+  exit(1);
+}
+
+} // namespace chronos
+
+#if WAF
+#include "controller.moc"
+#include "controller.cpp.moc"
+#endif
diff --git a/src/controller.h b/src/controller.h
new file mode 100644
index 0000000..85986c7
--- /dev/null
+++ b/src/controller.h
@@ -0,0 +1,226 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHRONOS_CONTROLLER_H
+#define CHRONOS_CONTROLLER_H
+
+#include <QDialog>
+#include <QMenu>
+#include <QSystemTrayIcon>
+#include <QtSql/QSqlDatabase>
+
+#include "setting-dialog.h"
+#include "start-chat-dialog.h"
+#include "profile-editor.h"
+#include "invitation-dialog.h"
+#include "contact-panel.h"
+#include "browse-contact-dialog.h"
+#include "add-contact-panel.h"
+#include "chat-dialog.h"
+
+#ifndef Q_MOC_RUN
+#include "contact-manager.h"
+#include "validator-invitation.h"
+#include <ndn-cpp-dev/face.hpp>
+#include <ndn-cpp-dev/security/key-chain.hpp>
+#endif
+
+namespace chronos {
+
+class Controller : public QDialog
+{
+  Q_OBJECT
+
+public: // public methods
+  Controller(ndn::shared_ptr<ndn::Face> face,
+             QWidget* parent = 0);
+  
+  virtual
+  ~Controller();
+
+private: // private methods
+  std::string
+  getDBName();
+
+  void
+  openDB();
+
+  void
+  initialize();
+
+  void
+  setInvitationListener();
+
+  void
+  loadConf();
+
+  void
+  saveConf();
+
+  void 
+  createActions();
+
+  void
+  createTrayIcon();
+
+  void
+  updateMenu();
+
+  void
+  onLocalPrefix(const ndn::Interest& interest, ndn::Data& data);
+
+  void
+  onLocalPrefixTimeout(const ndn::Interest& interest);
+
+  void
+  onInvitationInterest(const ndn::Name& prefix, const ndn::Interest& interest, size_t routingPrefixOffset);
+  
+  void
+  onInvitationRegisterFailed(const ndn::Name& prefix, const std::string& failInfo);
+
+  void
+  onInvitationValidated(const ndn::shared_ptr<const ndn::Interest>& interest);
+
+  void
+  onInvitationValidationFailed(const ndn::shared_ptr<const ndn::Interest>& interest, std::string failureInfo);
+
+  std::string
+  getRandomString();
+
+  ndn::Name
+  getInvitationRoutingPrefix();
+
+  void
+  addChatDialog(const QString& chatroomName, ChatDialog* chatDialog);
+
+signals:
+  void
+  closeDBModule();
+
+  void
+  localPrefixUpdated(const QString& localPrefix);
+
+  void
+  identityUpdated(const QString& identity);
+
+  void
+  refreshBrowseContact();
+
+private slots:
+  void
+  onIdentityUpdated(const QString& identity);
+
+  void
+  onIdentityUpdatedContinued();
+
+  void
+  onContactIdListReady(const QStringList& list);
+
+  void
+  onNickUpdated(const QString& nick);
+
+  void
+  onLocalPrefixUpdated(const QString& localPrefix);
+
+  void
+  onStartChatAction();
+
+  void
+  onSettingsAction();
+
+  void
+  onProfileEditorAction();
+
+  void
+  onAddContactAction();
+
+  void
+  onContactListAction();
+
+  void
+  onDirectAdd();
+
+  void
+  onUpdateLocalPrefixAction();
+
+  void
+  onMinimizeAction();
+
+  void
+  onQuitAction();
+
+  void
+  onStartChatroom(const QString& chatroom, bool secured);
+
+  void
+  onInvitationResponded(const ndn::Name& invitationName, bool accepted);
+
+  void
+  onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data);
+
+  void
+  onRemoveChatDialog(const QString& chatroom);
+
+  void
+  onWarning(const QString& msg);
+
+  void
+  onError(const QString& msg);
+
+private: // private member
+  typedef std::map<std::string, QAction*> ChatActionList;
+  typedef std::map<std::string, ChatDialog*> ChatDialogList;
+
+  // Communication
+  ndn::shared_ptr<ndn::Face>     m_face;
+  ndn::Name                      m_localPrefix;
+  const ndn::RegisteredPrefixId* m_invitationListenerId;
+
+  // Contact Manager
+  ContactManager m_contactManager;
+
+  // Tray
+  QAction*         m_startChatroom;
+  QAction*         m_minimizeAction;
+  QAction*         m_settingsAction;
+  QAction*         m_editProfileAction;
+  QAction*         m_contactListAction;
+  QAction*         m_addContactAction;
+  QAction*         m_updateLocalPrefixAction;
+  QAction*         m_quitAction;
+  QMenu*           m_trayIconMenu;
+  QMenu*           m_closeMenu;
+  QSystemTrayIcon* m_trayIcon;
+  ChatActionList   m_chatActionList;
+  ChatActionList   m_closeActionList;
+
+  // Dialogs
+  SettingDialog*       m_settingDialog;
+  StartChatDialog*     m_startChatDialog;
+  ProfileEditor*       m_profileEditor;
+  InvitationDialog*    m_invitationDialog;
+  ContactPanel*        m_contactPanel;
+  BrowseContactDialog* m_browseContactDialog;
+  AddContactPanel*     m_addContactPanel;
+  ChatDialogList       m_chatDialogList;
+
+  // Conf
+  ndn::Name   m_identity;
+  std::string m_nick;
+  QSqlDatabase m_db;
+
+  // Security related;
+  ndn::KeyChain                m_keyChain;
+  chronos::ValidatorInvitation m_validator;
+};
+
+} // namespace chronos
+
+#endif //CHRONOS_CONTROLLER_H
diff --git a/src/digesttreescene.cpp b/src/digesttreescene.cpp
index d692d4e..c2aa865 100644
--- a/src/digesttreescene.cpp
+++ b/src/digesttreescene.cpp
@@ -25,10 +25,8 @@
 
 //DisplayUserPtr DisplayUserNullPtr;
 
-DigestTreeScene::DigestTreeScene(ndn::shared_ptr<boost::asio::io_service> ioService,
-                                 QWidget *parent)
+DigestTreeScene::DigestTreeScene(QWidget *parent)
   : QGraphicsScene(parent)
-  , m_scheduler(*ioService)
 {
   previouslyUpdatedUser = DisplayUserNullPtr;
 }
@@ -60,7 +58,7 @@
   if (rePlot) 
   {
     plot(digest);
-    m_scheduler.scheduleEvent(ndn::time::milliseconds(600), ndn::bind(&DigestTreeScene::emitReplot, this));
+    QTimer::singleShot(2100, this, SLOT(emitReplot()));
   }
   else 
   {
diff --git a/src/digesttreescene.h b/src/digesttreescene.h
index c239a49..9f1c63f 100644
--- a/src/digesttreescene.h
+++ b/src/digesttreescene.h
@@ -19,7 +19,6 @@
 #include <QMap>
 
 #ifndef Q_MOC_RUN
-#include <ndn-cpp-dev/util/scheduler.hpp>
 #include <sync-seq-no.h>
 #include <sync-logic.h>
 #include <ctime>
@@ -45,8 +44,7 @@
 typedef QMapIterator<QString, DisplayUserPtr> RosterIterator;
 
 public:
-  DigestTreeScene(ndn::shared_ptr<boost::asio::io_service> ioService,
-                  QWidget *parent = 0);
+  DigestTreeScene(QWidget *parent = 0);
   void processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest);
   void msgReceived(QString prefix, QString nick);
   void clearAll();
@@ -73,7 +71,6 @@
   QGraphicsTextItem *m_rootDigest; 
   DisplayUserPtr previouslyUpdatedUser;
   QString m_currentPrefix;
-  ndn::Scheduler m_scheduler;
 };
 
 class User 
diff --git a/src/dns-storage.cpp b/src/dns-storage.cpp
deleted file mode 100644
index 5391edf..0000000
--- a/src/dns-storage.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "dns-storage.h"
-
-#include <boost/filesystem.hpp>
-#include "logging.h"
-
-
-using namespace std;
-using namespace ndn;
-using namespace ndn::ptr_lib;
-namespace fs = boost::filesystem;
-
-INIT_LOGGER("DnsStorage");
-
-namespace chronos{
-
-const string INIT_DD_TABLE = "\
-CREATE TABLE IF NOT EXISTS                                           \n \
-  DnsData(                                                           \n \
-      dns_identity  BLOB NOT NULL,                                   \n \
-      dns_name      BLOB NOT NULL,                                   \n \
-      dns_type      BLOB NOT NULL,                                   \n \
-      data_name     BLOB NOT NULL,                                   \n	\
-      dns_value     BLOB NOT NULL,                                   \n \
-                                                                     \
-      PRIMARY KEY (dns_identity, dns_name, dns_type)                 \n \
-  );                                                                 \
-CREATE INDEX dd_index ON DnsData(dns_identity, dns_name, dns_type);  \n \
-CREATE INDEX dd_index2 ON DnsData(data_name);                        \n \
-";
-
-DnsStorage::DnsStorage()
-{
-  fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
-  fs::create_directories (chronosDir);
-
-  int res = sqlite3_open((chronosDir / "dns.db").c_str (), &m_db);
-  if (res != SQLITE_OK)
-    throw Error("Chronos DNS DB cannot be open/created");
-
-  // Check if SelfProfile table exists
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='DnsData'", -1, &stmt, 0);
-  res = sqlite3_step (stmt);
-
-  bool ddTableExist = false;
-  if (res == SQLITE_ROW)
-      ddTableExist = true;
-  sqlite3_finalize (stmt);
-
-  if(!ddTableExist)
-    {
-      char *errmsg = 0;
-      res = sqlite3_exec (m_db, INIT_DD_TABLE.c_str (), NULL, NULL, &errmsg);
-      if (res != SQLITE_OK && errmsg != 0)
-        throw Error("Init \"error\" in DnsData");
-    }
-}
-
-void
-DnsStorage::updateDnsData(const ndn::Block& data, const std::string& identity, const std::string& name, const std::string& type, const string& dataName)
-{  
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "INSERT OR REPLACE INTO DnsData (dns_identity, dns_name, dns_type, dns_value, data_name) VALUES (?, ?, ?, ?, ?)", -1, &stmt, 0);
-  sqlite3_bind_text(stmt, 1, identity.c_str(), identity.size(), SQLITE_TRANSIENT);
-  sqlite3_bind_text(stmt, 2, name.c_str(), name.size(), SQLITE_TRANSIENT);
-  sqlite3_bind_text(stmt, 3, type.c_str(), type.size(), SQLITE_TRANSIENT);
-  sqlite3_bind_text(stmt, 4, (const char*)data.wire(), data.size(), SQLITE_TRANSIENT); 
-  sqlite3_bind_text(stmt, 5, dataName.c_str(), dataName.size(), SQLITE_TRANSIENT);
-  sqlite3_step(stmt);
-  sqlite3_finalize(stmt);
-}
-
-shared_ptr<Data>
-DnsStorage::getData(const Name& dataName)
-{
-  sqlite3_stmt *stmt;
-  sqlite3_prepare_v2 (m_db, "SELECT dns_value FROM DnsData where data_name=?", -1, &stmt, 0);
-  sqlite3_bind_text(stmt, 1, dataName.toUri().c_str(), dataName.toUri().size(), SQLITE_TRANSIENT);
-  
-  if(sqlite3_step (stmt) == SQLITE_ROW)
-    {
-      shared_ptr<Data> data = make_shared<Data>();
-      data->wireDecode(Block(reinterpret_cast<const uint8_t*>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0)));
-      sqlite3_finalize(stmt);
-      return data;
-    }
-  sqlite3_finalize(stmt);
-
-  return shared_ptr<Data>();
-}
-
-}//chronos
diff --git a/src/dns-storage.h b/src/dns-storage.h
deleted file mode 100644
index 89d3876..0000000
--- a/src/dns-storage.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef CHRONOS_DNS_STORAGE_H
-#define CHRONOS_DNS_STORAGE_H
-
-#include "config.h"
-#include <sqlite3.h>
-#include <ndn-cpp-dev/data.hpp>
-
-namespace chronos{
-
-class DnsStorage
-{
-public:
-  struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
-
-  DnsStorage();
-
-  ~DnsStorage()
-  { sqlite3_close(m_db); }
-
-  void
-  updateDnsSelfProfileData(const ndn::Data& data, const ndn::Name& identity)
-  { updateDnsData(data.wireEncode(), identity.toUri(), "N/A", "PROFILE", data.getName().toUri()); }
-
-  void
-  updateDnsEndorseOthers(const ndn::Data& data, const ndn::Name& identity, const ndn::Name& endorsee)
-  { updateDnsData(data.wireEncode(), identity.toUri(), endorsee.toUri(), "ENDORSEE", data.getName().toUri()); }
-  
-  void
-  updateDnsOthersEndorse(const ndn::Data& data, const ndn::Name& identity)
-  { updateDnsData(data.wireEncode(), identity.toUri(), "N/A", "ENDORSED", data.getName().toUri()); }
-
-  ndn::ptr_lib::shared_ptr<ndn::Data>
-  getData(const ndn::Name& name);
-
-private:
-  void
-  updateDnsData(const ndn::Block& data, const std::string& identity, const std::string& name, const std::string& type, const std::string& dataName);
-
-private:
-  sqlite3 *m_db;
-};
-
-}//chronos
-
-#endif
diff --git a/src/endorse-certificate.cpp b/src/endorse-certificate.cpp
index 21f5053..3d1f298 100644
--- a/src/endorse-certificate.cpp
+++ b/src/endorse-certificate.cpp
@@ -11,19 +11,17 @@
 #include "endorse-certificate.h"
 #include "endorse-extension.pb.h"
 #include <boost/iostreams/stream.hpp>
-#include "logging.h"
 
 using namespace std;
 using namespace ndn;
 
-
-INIT_LOGGER("EndorseCertificate");
-
 namespace chronos{
 
 const OID EndorseCertificate::PROFILE_EXT_OID("1.3.6.1.5.32.2.1");
 const OID EndorseCertificate::ENDORSE_EXT_OID("1.3.6.1.5.32.2.2");
 
+const std::vector<std::string> EndorseCertificate::DEFAULT_ENDORSE_LIST = std::vector<std::string>();
+
 Chronos::EndorseExtensionMsg&
 operator << (Chronos::EndorseExtensionMsg& endorseExtension, const vector<string>& endorseList)
 { 
@@ -106,6 +104,41 @@
   encode();
 }
 
+EndorseCertificate::EndorseCertificate(const Name& keyName,
+                                       const PublicKey& key,
+                                       MillisecondsSince1970 notBefore,
+                                       MillisecondsSince1970 notAfter,
+                                       const Name& signer,
+                                       const Profile& profile,
+                                       const vector<string>& endorseList)
+  : Certificate()
+  , m_keyName(keyName)
+  , m_signer(signer)
+  , m_profile(profile)
+  , m_endorseList(endorseList)
+{
+  Name dataName = m_keyName;
+  dataName.append("PROFILE-CERT").append(m_signer.wireEncode()).appendVersion();
+  setName(dataName);
+  
+  setNotBefore(notBefore);
+  setNotAfter(notAfter);
+  addSubjectDescription(CertificateSubjectDescription("2.5.4.41", m_keyName.toUri()));
+  setPublicKeyInfo(key);
+
+  OBufferStream profileStream;
+  m_profile.encode(profileStream);
+  addExtension(CertificateExtension(PROFILE_EXT_OID, true, *profileStream.buf()));
+
+  OBufferStream endorseStream;
+  Chronos::EndorseExtensionMsg endorseExtension;
+  endorseExtension << m_endorseList;
+  endorseExtension.SerializeToOstream(&endorseStream);
+  addExtension(CertificateExtension(ENDORSE_EXT_OID, true, *endorseStream.buf()));
+
+  encode();  
+}
+
 EndorseCertificate::EndorseCertificate(const EndorseCertificate& endorseCertificate)
   : Certificate(endorseCertificate)
   , m_keyName(endorseCertificate.m_keyName)
diff --git a/src/endorse-certificate.h b/src/endorse-certificate.h
index 7352a4d..42f255f 100644
--- a/src/endorse-certificate.h
+++ b/src/endorse-certificate.h
@@ -24,15 +24,25 @@
 public:
   struct Error : public ndn::Certificate::Error { Error(const std::string &what) : ndn::Certificate::Error(what) {} };
 
+  static const std::vector<std::string> DEFAULT_ENDORSE_LIST;
+
   EndorseCertificate() {}
 
   EndorseCertificate(const ndn::IdentityCertificate& kskCertificate,
                      const Profile& profile,
-                     const std::vector<std::string>& endorseList = std::vector<std::string>());
+                     const std::vector<std::string>& endorseList = DEFAULT_ENDORSE_LIST);
 
   EndorseCertificate(const EndorseCertificate& endorseCertificate,
                      const ndn::Name& signer,
-                     const std::vector<std::string>& endorseList);
+                     const std::vector<std::string>& endorseList = DEFAULT_ENDORSE_LIST);
+
+  EndorseCertificate(const ndn::Name& keyName,
+                     const ndn::PublicKey& key,
+                     ndn::MillisecondsSince1970 notBefore,
+                     ndn::MillisecondsSince1970 notAfter,
+                     const ndn::Name& signer,
+                     const Profile& profile,
+                     const std::vector<std::string>& endorseList = DEFAULT_ENDORSE_LIST);
 
   EndorseCertificate(const EndorseCertificate& endorseCertificate);
 
@@ -63,7 +73,7 @@
   static const ndn::OID ENDORSE_EXT_OID;
 
   ndn::Name m_keyName;
-  ndn::Name m_signer;
+  ndn::Name m_signer; // signing key name
   Profile m_profile;
   std::vector<std::string> m_endorseList;
 };
diff --git a/src/endorse-collection.proto b/src/endorse-collection.proto
index d3aa574..7aa1af8 100644
--- a/src/endorse-collection.proto
+++ b/src/endorse-collection.proto
@@ -1,10 +1,11 @@
-package Chronos;
+package chronos;
 
 message EndorseCollection
 {
   message Endorsement
   {
-    required string blob = 1;
+    required string certname = 1;
+    required string hash     = 2;
   }
   repeated Endorsement endorsement = 1;
 }
\ No newline at end of file
diff --git a/src/endorse-info.proto b/src/endorse-info.proto
new file mode 100644
index 0000000..a0612d0
--- /dev/null
+++ b/src/endorse-info.proto
@@ -0,0 +1,12 @@
+package chronos;
+
+message EndorseInfo
+{
+  message Endorsement
+  {
+    required string type    = 1;
+    required string value   = 2;
+    required string endorse = 3;
+  }
+  repeated Endorsement endorsement = 1;
+}
\ No newline at end of file
diff --git a/src/intro-cert-list.proto b/src/intro-cert-list.proto
new file mode 100644
index 0000000..6b65a83
--- /dev/null
+++ b/src/intro-cert-list.proto
@@ -0,0 +1,6 @@
+package Chronos;
+
+message IntroCertListMsg
+{
+  repeated string certname = 1;
+}
\ No newline at end of file
diff --git a/src/invitation-dialog.cpp b/src/invitation-dialog.cpp
new file mode 100644
index 0000000..8be49fc
--- /dev/null
+++ b/src/invitation-dialog.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+
+#include "invitation-dialog.h"
+#include "ui_invitation-dialog.h"
+
+using namespace std;
+using namespace ndn;
+
+InvitationDialog::InvitationDialog(QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::InvitationDialog)
+{
+    ui->setupUi(this);
+    
+    connect(ui->okButton, SIGNAL(clicked()),
+            this, SLOT(onOkClicked()));
+    connect(ui->cancelButton, SIGNAL(clicked()),
+            this, SLOT(onCancelClicked()));
+}
+
+InvitationDialog::~InvitationDialog()
+{
+    delete ui;
+}
+
+void
+InvitationDialog::setInvitation(const string& alias,
+                                const string& chatroom,
+                                const Name& interestName)
+{
+  string msg = alias;
+  msg.append(" invites you to: ").append(chatroom);
+  ui->msgLabel->setText(QString::fromStdString(msg));
+}
+
+void
+InvitationDialog::onOkClicked()
+{ 
+  emit invitationResponded(m_invitationInterest, true); 
+  this->close();
+
+  ui->msgLabel->clear();
+  m_invitationInterest.clear();
+}
+  
+void
+InvitationDialog::onCancelClicked()
+{ 
+  emit invitationResponded(m_invitationInterest, false);
+  this->close();
+
+  ui->msgLabel->clear();
+  m_invitationInterest.clear();
+}
+
+#if WAF
+#include "invitation-dialog.moc"
+#include "invitation-dialog.cpp.moc"
+#endif
diff --git a/src/invitationdialog.h b/src/invitation-dialog.h
similarity index 68%
rename from src/invitationdialog.h
rename to src/invitation-dialog.h
index 8edc04d..0112185 100644
--- a/src/invitationdialog.h
+++ b/src/invitation-dialog.h
@@ -8,15 +8,13 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef INVITATIONDIALOG_H
-#define INVITATIONDIALOG_H
+#ifndef INVITATION_DIALOG_H
+#define INVITATION_DIALOG_H
 
 #include <QDialog>
 
 #ifndef Q_MOC_RUN
-#include <ndn-cpp-dev/data.hpp>
-#include <ndn-cpp-dev/security/identity-certificate.hpp>
-#include "invitation.h"
+#include <ndn-cpp-dev/name.hpp>
 #endif
 
 namespace Ui {
@@ -33,14 +31,12 @@
 
   void
   setInvitation(const std::string& alias,
+                const std::string& chatroom,
                 const ndn::Name& invitationInterest);
 
 signals:
   void
-  invitationAccepted(const ndn::Name& invitationInterest);
-  
-  void
-  invitationRejected(const ndn::Name& invitationInterest);
+  invitationResponded(const ndn::Name& invitationName, bool accepted);
 
 private slots:
   void
@@ -52,8 +48,7 @@
 
 private:
   Ui::InvitationDialog *ui;
-  std::string m_inviterAlias;
   ndn::Name m_invitationInterest;
 };
 
-#endif // INVITATIONDIALOG_H
+#endif // INVITATION_DIALOG_H
diff --git a/src/invitation-dialog.ui b/src/invitation-dialog.ui
new file mode 100644
index 0000000..ec8e9f6
--- /dev/null
+++ b/src/invitation-dialog.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InvitationDialog</class>
+ <widget class="QDialog" name="InvitationDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>150</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout" stretch="5,1">
+     <property name="leftMargin">
+      <number>10</number>
+     </property>
+     <property name="topMargin">
+      <number>10</number>
+     </property>
+     <property name="rightMargin">
+      <number>10</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="msgLabel">
+       <property name="text">
+        <string>TextLabel</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="buttonLayout" stretch="1,1">
+       <property name="spacing">
+        <number>-1</number>
+       </property>
+       <property name="leftMargin">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="QPushButton" name="cancelButton">
+         <property name="text">
+          <string>Reject</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="okButton">
+         <property name="text">
+          <string>Accept</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/invitation.cpp b/src/invitation.cpp
index 9495cec..4aa3358 100644
--- a/src/invitation.cpp
+++ b/src/invitation.cpp
@@ -23,14 +23,14 @@
 
 namespace chronos{
 
-const size_t  Invitation::NAME_SIZE_MIN  = 9;
-const size_t  Invitation::INVITEE_START  = 4;
-const ssize_t Invitation::SIGNATURE      = -1;
-const ssize_t Invitation::KEY_LOCATOR    = -2;
-const ssize_t Invitation::TIMESTAMP      = -3;
-const ssize_t Invitation::INVITER_PREFIX = -4;
-const ssize_t Invitation::CHATROOM       = -5;
-const Name    Invitation::INVITATION_PREFIX("/ndn/broadcast/chronos/chat-invitation");
+const size_t  Invitation::NAME_SIZE_MIN         = 7;
+const ssize_t Invitation::SIGNATURE             = -1;
+const ssize_t Invitation::KEY_LOCATOR           = -2;
+const ssize_t Invitation::TIMESTAMP             = -3;
+const ssize_t Invitation::INVITER_CERT          = -4;
+const ssize_t Invitation::INVITER_PREFIX        = -5;
+const ssize_t Invitation::CHATROOM              = -6;
+const ssize_t Invitation::CHRONOCHAT_INVITATION = -7;
 
 
 Invitation::Invitation(const Name& interestName)
@@ -39,25 +39,34 @@
 
   if(nameSize < NAME_SIZE_MIN)
     throw Error("Wrong Invitation Name: Wrong length"); 
- 
-  if(!INVITATION_PREFIX.isPrefixOf(interestName))
-    throw Error("Wrong Invitation Name: Wrong invitation prefix");
 
-  m_interestName = interestName.getPrefix(-3);
+  if(interestName.get(CHRONOCHAT_INVITATION).toEscapedString() != "CHRONOCHAT-INVITATION")
+    throw Error("Wrong Invitation Name: Wrong application tags");
+
+  m_interestName = interestName.getPrefix(KEY_LOCATOR);
+  m_timestamp = interestName.get(TIMESTAMP).toNumber();
+  m_inviterCertificate.wireDecode(interestName.get(INVITER_CERT).blockFromValue());
   m_inviterRoutingPrefix.wireDecode(interestName.get(INVITER_PREFIX).blockFromValue());
-  m_chatroom.wireDecode(interestName.get(CHATROOM).blockFromValue());
-  m_inviteeNameSpace = interestName.getSubName(INVITEE_START, nameSize - NAME_SIZE_MIN);  
+  m_chatroom = interestName.get(CHATROOM).toEscapedString();  
+  m_inviteeNameSpace = interestName.getPrefix(CHRONOCHAT_INVITATION);  
 }
 
-Invitation::Invitation(const Name &inviteeNameSpace,
-                       const Name &chatroom,
-                       const Name &inviterRoutingPrefix)
+Invitation::Invitation(const Name& inviteeNameSpace,
+                       const string& chatroom,
+                       const Name& inviterRoutingPrefix,
+                       const IdentityCertificate& inviterCertificate)
   : m_inviteeNameSpace(inviteeNameSpace)
   , m_chatroom(chatroom)
   , m_inviterRoutingPrefix(inviterRoutingPrefix)
-{  
-  m_interestName = INVITATION_PREFIX;
-  m_interestName.append(inviteeNameSpace).append(chatroom.wireEncode()).append(inviterRoutingPrefix.wireEncode());
+  , m_inviterCertificate(inviterCertificate)
+  , m_timestamp(time::now())
+{
+  m_interestName = m_inviteeNameSpace;
+  m_interestName.append("CHRONOCHAT-INVITATION")
+    .append(m_chatroom)
+    .append(m_inviterRoutingPrefix.wireEncode())
+    .append(m_inviterCertificate.wireEncode())
+    .append(name::Component::fromNumber(m_timestamp));
 }
 
 Invitation::Invitation(const Invitation& invitation)
@@ -65,6 +74,9 @@
   , m_inviteeNameSpace(invitation.m_inviteeNameSpace)
   , m_chatroom(invitation.m_chatroom)
   , m_inviterRoutingPrefix(invitation.m_inviterRoutingPrefix)
-{}
+  , m_inviterCertificate(invitation.m_inviterCertificate)
+  , m_timestamp(invitation.m_timestamp)
+{
+}
 
 }//chronos
diff --git a/src/invitation.h b/src/invitation.h
index ba850ac..d002402 100644
--- a/src/invitation.h
+++ b/src/invitation.h
@@ -14,33 +14,42 @@
 
 #include <ndn-cpp-dev/name.hpp>
 #include <ndn-cpp-dev/signature.hpp>
+#include <ndn-cpp-dev/security/identity-certificate.hpp>
 
 namespace chronos{
 
 class Invitation
 {
-/*
- * /ndn/broadcast/chronos/invitation/[invitee_namespace]/<chatroom_name>/<inviter_routing_prefix>/<timestamp>/<keylocator>/<signature>
- */
+  public:
+  /*
+   *  /[invitee_namespace]
+   *  /CHRONOCHAT-INVITATION
+   *  /<chatroom_name>
+   *  /<inviter_routing_prefix>
+   *  /<inviter_cert>
+   *  /<timestamp>
+   *  /<keylocator>
+   *  /<signature>
+   */
   static const size_t NAME_SIZE_MIN;
-  static const size_t INVITEE_START;
   static const ssize_t SIGNATURE;
   static const ssize_t KEY_LOCATOR;
   static const ssize_t TIMESTAMP;
+  static const ssize_t INVITER_CERT;
   static const ssize_t INVITER_PREFIX;
   static const ssize_t CHATROOM;
-  static const ndn::Name INVITATION_PREFIX;
+  static const ssize_t CHRONOCHAT_INVITATION;
 
-public:
   struct Error : public std::runtime_error { Error(const std::string &what) : std::runtime_error(what) {} };
 
   Invitation() {}
 
   Invitation(const ndn::Name& interestName);
 
-  Invitation(const ndn::Name &inviteeNameSpace,
-             const ndn::Name &chatroom,
-             const ndn::Name &inviterRoutingPrefix);
+  Invitation(const ndn::Name& inviteeNameSpace,
+             const std::string& chatroom,
+             const ndn::Name& inviterRoutingPrefix,
+             const ndn::IdentityCertificate& inviterCertificate);
 
   Invitation(const Invitation& invitation);
 
@@ -51,13 +60,21 @@
   getInviteeNameSpace() const
   { return m_inviteeNameSpace; }
 
-  const ndn::Name&
+  const std::string&
   getChatroom() const
   { return m_chatroom; }
 
   const ndn::Name&
   getInviterRoutingPrefix() const
   { return m_inviterRoutingPrefix; }
+
+  const ndn::IdentityCertificate&
+  getInviterCertificate() const
+  { return m_inviterCertificate; }
+
+  const uint64_t
+  getTimestamp() const
+  { return m_timestamp; }
   
   const ndn::Name&
   getUnsignedInterestName() const
@@ -67,8 +84,10 @@
   ndn::Name m_interestName;
 
   ndn::Name m_inviteeNameSpace;
-  ndn::Name m_chatroom;
+  std::string m_chatroom;
   ndn::Name m_inviterRoutingPrefix;
+  ndn::IdentityCertificate m_inviterCertificate;
+  uint64_t m_timestamp;
 };
 
 }//chronos
diff --git a/src/invitationdialog.cpp b/src/invitationdialog.cpp
deleted file mode 100644
index 2a1d21f..0000000
--- a/src/invitationdialog.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-
-#include "invitationdialog.h"
-#include "ui_invitationdialog.h"
-
-using namespace std;
-using namespace ndn;
-using namespace chronos;
-
-InvitationDialog::InvitationDialog(QWidget *parent) :
-    QDialog(parent),
-    ui(new Ui::InvitationDialog)
-{
-    ui->setupUi(this);
-    
-    connect(ui->okButton, SIGNAL(clicked()),
-            this, SLOT(onOkClicked()));
-    connect(ui->cancelButton, SIGNAL(clicked()),
-            this, SLOT(onCancelClicked()));
-}
-
-InvitationDialog::~InvitationDialog()
-{
-    delete ui;
-}
-
-void
-InvitationDialog::setInvitation(const string& alias,
-                                const Name& interestName)
-{
-  m_inviterAlias = alias;
-  string msg = alias;
-  msg.append("\ninvites you to join the chat room: ");
-  ui->msgLabel->setText(QString::fromStdString(msg));
-
-  m_invitationInterest = interestName;
-  Invitation invitation(interestName);
-  ui->chatroomLine->setText(QString::fromStdString(invitation.getChatroom().get(0).toEscapedString()));
-}
-
-void
-InvitationDialog::onOkClicked()
-{ 
-  emit invitationAccepted(m_invitationInterest); 
-  this->close();
-}
-  
-void
-InvitationDialog::onCancelClicked()
-{ 
-  ui->msgLabel->clear();
-  ui->chatroomLine->clear();
-
-  emit invitationRejected(m_invitationInterest); 
-
-  m_invitationInterest.clear();
-  m_inviterAlias.clear();
-
-  this->close();
-}
-
-#if WAF
-#include "invitationdialog.moc"
-#include "invitationdialog.cpp.moc"
-#endif
diff --git a/src/invitationdialog.ui b/src/invitationdialog.ui
deleted file mode 100644
index 0348293..0000000
--- a/src/invitationdialog.ui
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>InvitationDialog</class>
- <widget class="QDialog" name="InvitationDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>300</width>
-    <height>200</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <widget class="QLabel" name="msgLabel">
-   <property name="geometry">
-    <rect>
-     <x>30</x>
-     <y>30</y>
-     <width>240</width>
-     <height>50</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>TextLabel</string>
-   </property>
-   <property name="alignment">
-    <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
-   </property>
-  </widget>
-  <widget class="QLineEdit" name="chatroomLine">
-   <property name="geometry">
-    <rect>
-     <x>30</x>
-     <y>100</y>
-     <width>241</width>
-     <height>21</height>
-    </rect>
-   </property>
-   <property name="readOnly">
-    <bool>true</bool>
-   </property>
-  </widget>
-  <widget class="QPushButton" name="cancelButton">
-   <property name="geometry">
-    <rect>
-     <x>30</x>
-     <y>150</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>Reject</string>
-   </property>
-  </widget>
-  <widget class="QPushButton" name="okButton">
-   <property name="geometry">
-    <rect>
-     <x>170</x>
-     <y>150</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>Accept</string>
-   </property>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/invite-list-dialog.cpp b/src/invite-list-dialog.cpp
new file mode 100644
index 0000000..c46036f
--- /dev/null
+++ b/src/invite-list-dialog.cpp
@@ -0,0 +1,85 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "invite-list-dialog.h"
+#include "ui_invite-list-dialog.h"
+
+using namespace std;
+
+InviteListDialog::InviteListDialog(QWidget *parent) 
+  :QDialog(parent)
+  , ui(new Ui::InviteListDialog)
+  , m_contactListModel(new QStringListModel)
+{
+  ui->setupUi(this);
+
+  ui->contactListView->setModel(m_contactListModel);
+
+  connect(ui->inviteButton, SIGNAL(clicked()),
+	  this, SLOT(onInviteClicked()));
+  connect(ui->cancelButton, SIGNAL(clicked()),
+	  this, SLOT(onCancelClicked()));
+}
+
+InviteListDialog::~InviteListDialog()
+{
+  delete ui;
+  delete m_contactListModel;
+}
+
+void
+InviteListDialog::setInviteLabel(string label)
+{ 
+  string msg("invite to chatroom:\n");
+  msg += label;
+  ui->inviteLabel->setText(QString::fromStdString(msg));
+}
+
+void
+InviteListDialog::onInviteClicked()
+{
+  QModelIndexList selected = ui->contactListView->selectionModel()->selectedIndexes();
+  QString alias = m_contactListModel->data(selected.first(), Qt::DisplayRole).toString();
+
+  for(int i = 0; i < m_contactAliasList.size(); i++) // TODO:: could be optimized without using for loop.
+    {
+      if(alias == m_contactAliasList[i])
+        {
+          emit sendInvitation(m_contactIdList[i]);
+          break;
+        }
+    }
+
+  this->close();
+}
+
+void
+InviteListDialog::onCancelClicked()
+{
+  this->close();
+}
+
+void
+InviteListDialog::onContactAliasListReady(const QStringList& aliasList)
+{
+  m_contactAliasList = aliasList;
+  m_contactListModel->setStringList(m_contactAliasList);
+}
+
+void
+InviteListDialog::onContactIdListReady(const QStringList& idList)
+{
+  m_contactIdList = idList;
+}
+
+#if WAF
+#include "invite-list-dialog.moc"
+#include "invite-list-dialog.cpp.moc"
+#endif
diff --git a/src/invite-list-dialog.h b/src/invite-list-dialog.h
new file mode 100644
index 0000000..f5144fc
--- /dev/null
+++ b/src/invite-list-dialog.h
@@ -0,0 +1,62 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef INVITE_LIST_DIALOG_H
+#define INVITE_LIST_DIALOG_H
+
+#include <QDialog>
+#include <QStringListModel>
+
+#ifndef Q_MOC_RUN
+#endif
+
+namespace Ui {
+class InviteListDialog;
+}
+
+class InviteListDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit
+  InviteListDialog(QWidget *parent = 0);
+  
+  ~InviteListDialog();
+
+  void
+  setInviteLabel(std::string label);
+  
+signals:
+  void
+  sendInvitation(const QString&);
+
+public slots:
+  void
+  onContactAliasListReady(const QStringList& aliasList);
+
+  void
+  onContactIdListReady(const QStringList& idList);
+
+private slots:
+  void 
+  onInviteClicked();
+
+  void
+  onCancelClicked();
+
+private:
+  Ui::InviteListDialog *ui;
+  QStringListModel* m_contactListModel;
+  QStringList m_contactAliasList;
+  QStringList m_contactIdList;
+};
+
+#endif // INVITE_LIST_DIALOG_H
diff --git a/src/invite-list-dialog.ui b/src/invite-list-dialog.ui
new file mode 100644
index 0000000..157c9e3
--- /dev/null
+++ b/src/invite-list-dialog.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InviteListDialog</class>
+ <widget class="QDialog" name="InviteListDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout" stretch="4,20,2">
+     <property name="spacing">
+      <number>10</number>
+     </property>
+     <item>
+      <widget class="QLabel" name="inviteLabel">
+       <property name="font">
+        <font>
+         <weight>75</weight>
+         <bold>true</bold>
+        </font>
+       </property>
+       <property name="text">
+        <string>TextLabel</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QListView" name="contactListView"/>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <item>
+        <widget class="QPushButton" name="cancelButton">
+         <property name="text">
+          <string>Cancel</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="inviteButton">
+         <property name="text">
+          <string>Invite</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/invitelistdialog.cpp b/src/invitelistdialog.cpp
deleted file mode 100644
index 50fa50f..0000000
--- a/src/invitelistdialog.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "invitelistdialog.h"
-#include "ui_invitelistdialog.h"
-
-using namespace std;
-using namespace chronos;
-
-InviteListDialog::InviteListDialog(ndn::shared_ptr<ContactManager> contactManager,
-				   QWidget *parent) 
-  :QDialog(parent)
-  , ui(new Ui::InviteListDialog)
-  , m_contactManager(contactManager)
-  , m_contactListModel(new QStringListModel)
-{
-  ui->setupUi(this);
-
-  refreshContactList();
-
-  ui->contactListView->setModel(m_contactListModel);
-
-  connect(ui->inviteButton, SIGNAL(clicked()),
-	  this, SLOT(inviteWrapper()));
-  connect(ui->cancelButton, SIGNAL(clicked()),
-	  this, SLOT(onCancelClicked()));
-}
-
-InviteListDialog::~InviteListDialog()
-{
-  delete ui;
-  delete m_contactListModel;
-}
-
-void
-InviteListDialog::setInviteLabel(string label)
-{ 
-  string msg("invite to chatroom:\n");
-  msg += label;
-  ui->inviteLabel->setText(QString::fromStdString(msg)); 
-  refreshContactList();
-}
-
-void
-InviteListDialog::refreshContactList()
-{
-  m_contactList.clear();
-  m_contactManager->getContactItemList(m_contactList);
-  QStringList contactNameList;
-  for(int i = 0; i < m_contactList.size(); i++)
-    {
-      contactNameList << QString::fromStdString(m_contactList[i]->getAlias());
-    }
-
-  m_contactListModel->setStringList(contactNameList);
-}
-
-void
-InviteListDialog::inviteWrapper()
-{
-  QModelIndexList selected = ui->contactListView->selectionModel()->selectedIndexes();
-  QString text = m_contactListModel->data(selected.first(), Qt::DisplayRole).toString();
-  string alias = text.toStdString();
-
-  int i = 0;
-  for(; i < m_contactList.size(); i++)
-    {
-      if(alias == m_contactList[i]->getAlias())
-        break;
-    }
-
-  QString invitedContactNamespace = QString::fromStdString(m_contactList[i]->getNameSpace().toUri());
-
-  bool isIntroducer = true;
-
-  emit invitionDetermined(invitedContactNamespace, isIntroducer);
-
-  this->close();
-}
-
-void
-InviteListDialog::onCancelClicked()
-{ this->close(); }
-
-#if WAF
-#include "invitelistdialog.moc"
-#include "invitelistdialog.cpp.moc"
-#endif
diff --git a/src/invitelistdialog.h b/src/invitelistdialog.h
deleted file mode 100644
index 83e1b50..0000000
--- a/src/invitelistdialog.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef INVITELISTDIALOG_H
-#define INVITELISTDIALOG_H
-
-#include <QDialog>
-#include <QStringListModel>
-
-#ifndef Q_MOC_RUN
-#include "contact-manager.h"
-#endif
-
-namespace Ui {
-class InviteListDialog;
-}
-
-class InviteListDialog : public QDialog
-{
-  Q_OBJECT
-
-public:
-  explicit InviteListDialog(ndn::shared_ptr<chronos::ContactManager> contactManager,
-                            QWidget *parent = 0);
-  ~InviteListDialog();
-
-  void
-  setInviteLabel(std::string label);
-  
-signals:
-  void
-  invitionDetermined(QString, bool);
-
-private slots:
-  void
-  refreshContactList();
-
-  void 
-  inviteWrapper();
-
-  void
-  onCancelClicked();
-
-private:
-  Ui::InviteListDialog *ui;
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-  QStringListModel* m_contactListModel;
-  std::vector<ndn::shared_ptr<chronos::ContactItem> > m_contactList;
-  std::vector<std::string> m_invitedContacts;
-};
-
-#endif // INVITELISTDIALOG_H
diff --git a/src/invitelistdialog.ui b/src/invitelistdialog.ui
deleted file mode 100644
index 71c0fe3..0000000
--- a/src/invitelistdialog.ui
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>InviteListDialog</class>
- <widget class="QDialog" name="InviteListDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>300</width>
-    <height>400</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <widget class="QWidget" name="layoutWidget">
-   <property name="geometry">
-    <rect>
-     <x>10</x>
-     <y>10</y>
-     <width>281</width>
-     <height>381</height>
-    </rect>
-   </property>
-   <layout class="QVBoxLayout" name="verticalLayout" stretch="4,1,20,2">
-    <property name="spacing">
-     <number>10</number>
-    </property>
-    <item>
-     <widget class="QLabel" name="inviteLabel">
-      <property name="font">
-       <font>
-        <weight>75</weight>
-        <bold>true</bold>
-       </font>
-      </property>
-      <property name="text">
-       <string>TextLabel</string>
-      </property>
-      <property name="alignment">
-       <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <widget class="QCheckBox" name="isIntroducer">
-      <property name="text">
-       <string>as introducer</string>
-      </property>
-      <property name="checkable">
-       <bool>true</bool>
-      </property>
-      <property name="checked">
-       <bool>false</bool>
-      </property>
-      <property name="tristate">
-       <bool>false</bool>
-      </property>
-     </widget>
-    </item>
-    <item>
-     <widget class="QListView" name="contactListView"/>
-    </item>
-    <item>
-     <layout class="QHBoxLayout" name="horizontalLayout">
-      <item>
-       <widget class="QPushButton" name="cancelButton">
-        <property name="text">
-         <string>Cancel</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="inviteButton">
-        <property name="text">
-         <string>Invite</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/main.cpp b/src/main.cpp
index 030ba43..009f761 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -9,12 +9,9 @@
  */
 
 #include <QApplication>
-#include <QSystemTrayIcon>
+// #include <QSystemTrayIcon>
 
-#include "contactpanel.h"
-#include "contact-storage.h"
-#include "dns-storage.h"
-#include "contact-manager.h"
+#include "controller.h"
 #include "logging.h"
 #include <ndn-cpp-dev/face.hpp>
 #include <boost/thread/thread.hpp>
@@ -57,11 +54,9 @@
   NewApp app(argc, argv);
   
   shared_ptr<Face> face = make_shared<Face>();
-  ContactPanel contactPanel(face);
+  chronos::Controller controller(face);
 
-  contactPanel.show ();
-  contactPanel.activateWindow ();
-  contactPanel.raise ();
+  app.setQuitOnLastWindowClosed(false);
 
   boost::thread (runIO, face->ioService());
   
diff --git a/src/profile-data.cpp b/src/profile-data.cpp
deleted file mode 100644
index 98ce957..0000000
--- a/src/profile-data.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "profile-data.h"
-
-#include "logging.h"
-
-using namespace ndn;
-using namespace std;
-
-INIT_LOGGER("ProfileData");
-
-namespace chronos{
-
-ProfileData::ProfileData()
-  : Data()
-{}
-
-ProfileData::ProfileData(const Profile& profile)
-  : Data()
-  , m_identity(profile.getIdentityName())
-  , m_profile(profile)
-{
-  Name dataName = m_identity;
-  dataName.append("PROFILE").appendVersion();
-  setName(dataName);
-
-  OBufferStream os;
-  profile.encode(os);
-  setContent(os.buf());
-}
-
-ProfileData::ProfileData(const Data& data)
-  : Data(data)
-{
-  if(data.getName().get(-2).toEscapedString() == "PROFILE")
-    throw Error("No PROFILE component in data name!");
-
-  m_identity = data.getName().getPrefix(-2);
-
-  boost::iostreams::stream <boost::iostreams::array_source> is 
-    (reinterpret_cast<const char*>(data.getContent().value()), data.getContent().value_size());
-
-  m_profile.decode(is);
-}
-
-}//chronos
diff --git a/src/profile-data.h b/src/profile-data.h
deleted file mode 100644
index 47fe910..0000000
--- a/src/profile-data.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef CHRONOS_PROFILE_DATA_H
-#define CHRONOS_PROFILE_DATA_H
-
-#include "profile.h"
-#include <ndn-cpp-dev/data.hpp>
-
-
-namespace chronos{
-
-class ProfileData : public ndn::Data
-{
-public:
-  struct Error : public ndn::Data::Error { Error(const std::string &what) : ndn::Data::Error(what) {} };
-
-  ProfileData();
-
-  ProfileData(const Profile& profile);
-
-  ProfileData(const ndn::Data& data);
-
-  ~ProfileData() {}
-
-  const ndn::Name& 
-  getIdentityName() const
-  { return m_identity; }
-
-  const Profile&
-  getProfile() const
-  { return m_profile; }
-
-private:
-  ndn::Name m_identity;
-  Profile m_profile;
-};
-
-}//chronos
-
-#endif
diff --git a/src/profile-editor.cpp b/src/profile-editor.cpp
new file mode 100644
index 0000000..ac5dcbf
--- /dev/null
+++ b/src/profile-editor.cpp
@@ -0,0 +1,108 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "profile-editor.h"
+#include "ui_profile-editor.h"
+#include <QtSql/QSqlRecord>
+#include <QtSql/QSqlField>
+#include <QtSql/QSqlError>
+
+#ifndef Q_MOC_RUN
+#include "logging.h"
+#endif
+
+INIT_LOGGER("ProfileEditor")
+
+using namespace std;
+
+ProfileEditor::ProfileEditor(QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::ProfileEditor)
+  , m_tableModel(new QSqlTableModel())
+{
+  ui->setupUi(this);
+
+  connect(ui->addRowButton, SIGNAL(clicked()),
+          this, SLOT(onAddClicked()));
+  connect(ui->deleteRowButton, SIGNAL(clicked()),
+          this, SLOT(onDeleteClicked()));
+  connect(ui->okButton, SIGNAL(clicked()),
+          this, SLOT(onOkClicked()));
+}
+
+ProfileEditor::~ProfileEditor()
+{
+    delete ui;
+    delete m_tableModel;
+}
+
+void
+ProfileEditor::onCloseDBModule()
+{
+  _LOG_DEBUG("close db module");
+  if(m_tableModel)
+    {
+      delete m_tableModel;
+      _LOG_DEBUG("tableModel closed");
+    }
+}
+
+void
+ProfileEditor::onIdentityUpdated(const QString& identity)
+{
+  m_tableModel = new QSqlTableModel();
+
+  m_identity = identity;
+  ui->identityInput->setText(identity);
+  
+  m_tableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
+  m_tableModel->setTable("SelfProfile");
+  m_tableModel->select();
+  m_tableModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Type"));
+  m_tableModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Value"));
+
+  ui->profileTable->setModel(m_tableModel);
+  ui->profileTable->show();
+}
+
+void
+ProfileEditor::onAddClicked()
+{
+  int rowCount = m_tableModel->rowCount();
+  QSqlRecord record;
+  m_tableModel->insertRow(rowCount);
+  m_tableModel->setRecord(rowCount, record);
+}
+
+void
+ProfileEditor::onDeleteClicked()
+{
+  QItemSelectionModel* selectionModel = ui->profileTable->selectionModel();
+  QModelIndexList indexList = selectionModel->selectedIndexes();
+
+  int i = indexList.size() - 1;  
+  for(; i >= 0; i--)
+    m_tableModel->removeRow(indexList[i].row());
+    
+  m_tableModel->submitAll();
+}
+
+void
+ProfileEditor::onOkClicked()
+{
+  m_tableModel->submitAll();
+  emit updateProfile();
+  this->hide();
+}
+
+#if WAF
+#include "profile-editor.moc"
+#include "profile-editor.cpp.moc"
+#endif
diff --git a/src/profile-editor.h b/src/profile-editor.h
new file mode 100644
index 0000000..24c7aa2
--- /dev/null
+++ b/src/profile-editor.h
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef PROFILE_EDITOR_H
+#define PROFILE_EDITOR_H
+
+#include <QDialog>
+#include <QtSql/QSqlTableModel>
+
+#ifndef Q_MOC_RUN
+#endif
+
+namespace Ui {
+class ProfileEditor;
+}
+
+class ProfileEditor : public QDialog
+{
+    Q_OBJECT
+
+public:
+  explicit ProfileEditor(QWidget *parent = 0);
+  
+  ~ProfileEditor();
+
+public slots:
+  void
+  onCloseDBModule();
+
+  void
+  onIdentityUpdated(const QString& identity);
+  
+private slots:
+  void
+  onAddClicked();
+
+  void
+  onDeleteClicked();
+
+  void
+  onOkClicked();
+
+signals:
+  void
+  updateProfile();
+
+private:
+  Ui::ProfileEditor *ui;
+  QSqlTableModel* m_tableModel;
+  QString m_identity;
+};
+
+#endif // PROFILE_EDITOR_H
diff --git a/src/profile-editor.ui b/src/profile-editor.ui
new file mode 100644
index 0000000..b555d43
--- /dev/null
+++ b/src/profile-editor.ui
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProfileEditor</class>
+ <widget class="QDialog" name="ProfileEditor">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>500</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Profile Editor</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QVBoxLayout" name="profileEditorLayout" stretch="0,20,1">
+     <item>
+      <layout class="QHBoxLayout" name="identityLayout" stretch="2,4">
+       <item>
+        <widget class="QLabel" name="identityLabel">
+         <property name="font">
+          <font>
+           <weight>75</weight>
+           <bold>true</bold>
+          </font>
+         </property>
+         <property name="text">
+          <string>Current identity:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLineEdit" name="identityInput">
+         <property name="readOnly">
+          <bool>true</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <widget class="QTableView" name="profileTable">
+       <attribute name="horizontalHeaderCascadingSectionResizes">
+        <bool>false</bool>
+       </attribute>
+       <attribute name="horizontalHeaderDefaultSectionSize">
+        <number>100</number>
+       </attribute>
+       <attribute name="horizontalHeaderShowSortIndicator" stdset="0">
+        <bool>true</bool>
+       </attribute>
+       <attribute name="horizontalHeaderStretchLastSection">
+        <bool>true</bool>
+       </attribute>
+       <attribute name="verticalHeaderVisible">
+        <bool>true</bool>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="buttonLayout" stretch="1,1,1">
+       <item>
+        <widget class="QPushButton" name="addRowButton">
+         <property name="text">
+          <string>Add</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="deleteRowButton">
+         <property name="text">
+          <string>Delete</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="okButton">
+         <property name="text">
+          <string>OK</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/profile.h b/src/profile.h
index e085e77..982c5d8 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -83,6 +83,9 @@
   inline bool
   operator == (const Profile& profile) const;
 
+  inline bool
+  operator != (const Profile& profile) const;
+
 private:
   static const std::string OID_NAME;
   static const std::string OID_ORG;
@@ -100,7 +103,7 @@
 Chronos::ProfileMsg&
 operator >> (Chronos::ProfileMsg& msg, Profile& profile);
 
-bool
+inline bool
 Profile::operator == (const Profile& profile) const
 {
   if(m_entries.size() != profile.m_entries.size())
@@ -119,6 +122,12 @@
   return true;
 }
 
+inline bool
+Profile::operator != (const Profile& profile) const
+{
+  return !(*this == profile);
+}
+
 }//chronos
 
 #endif
diff --git a/src/profile.proto b/src/profile.proto
index e9b15e8..586c5c0 100644
--- a/src/profile.proto
+++ b/src/profile.proto
@@ -7,5 +7,5 @@
     required string oid = 1;
     required string data = 2;
   }
-  repeated ProfileEntry entry = 2;
+  repeated ProfileEntry entry = 1;
 }
\ No newline at end of file
diff --git a/src/profileeditor.cpp b/src/profileeditor.cpp
deleted file mode 100644
index 17931d0..0000000
--- a/src/profileeditor.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "profileeditor.h"
-#include "ui_profileeditor.h"
-#include <QtSql/QSqlRecord>
-#include <QtSql/QSqlField>
-#include <QtSql/QSqlError>
-
-#ifndef Q_MOC_RUN
-#include "logging.h"
-#endif
-
-using namespace ndn;
-using namespace std;
-using namespace chronos;
-
-INIT_LOGGER("ProfileEditor");
-
-ProfileEditor::ProfileEditor(shared_ptr<ContactManager> contactManager, 
-                             QWidget *parent) 
-    : QDialog(parent)
-    , ui(new Ui::ProfileEditor)
-    , m_tableModel(new QSqlTableModel())
-    , m_contactManager(contactManager)
-    , m_keyChain(new KeyChain())
-{
-  ui->setupUi(this);
-  
-  m_currentIdentity = contactManager->getDefaultIdentity();
-  ui->identityInput->setText(m_currentIdentity.toUri().c_str());
-
-  connect(ui->addRowButton, SIGNAL(clicked()),
-          this, SLOT(onAddClicked()));
-  connect(ui->deleteRowButton, SIGNAL(clicked()),
-          this, SLOT(onDeleteClicked()));
-  connect(ui->okButton, SIGNAL(clicked()),
-          this, SLOT(onOkClicked()));
-  connect(ui->getButton, SIGNAL(clicked()),
-          this, SLOT(onGetClicked()));
-
-
-
-}
-
-ProfileEditor::~ProfileEditor()
-{
-    delete ui;
-    delete m_tableModel;
-}
-
-void
-ProfileEditor::onAddClicked()
-{
-  int rowCount = m_tableModel->rowCount();
-  QSqlRecord record;
-  QSqlField identityField("profile_identity", QVariant::String);
-  record.append(identityField);
-  record.setValue("profile_identity", QString(m_currentIdentity.toUri().c_str()));
-  m_tableModel->insertRow(rowCount);
-  m_tableModel->setRecord(rowCount, record);
-}
-
-void
-ProfileEditor::onDeleteClicked()
-{
-  QItemSelectionModel* selectionModel = ui->profileTable->selectionModel();
-  QModelIndexList indexList = selectionModel->selectedIndexes();
-
-  int i = indexList.size() - 1;  
-  for(; i >= 0; i--)
-    m_tableModel->removeRow(indexList[i].row());
-    
-  m_tableModel->submitAll();
-}
-
-void
-ProfileEditor::onOkClicked()
-{
-  m_tableModel->submitAll();
-  m_contactManager->updateProfileData(m_currentIdentity);
-  this->hide();
-}
-
-void
-ProfileEditor::onGetClicked()
-{
-  QString inputIdentity = ui->identityInput->text();
-  m_currentIdentity = Name(inputIdentity.toUtf8().constData());
-  string filter("profile_identity = '");
-  filter.append(m_currentIdentity.toUri()).append("'");
-
-  m_tableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
-  m_tableModel->setTable("SelfProfile");
-  m_tableModel->setFilter(filter.c_str());
-  m_tableModel->select();
-  m_tableModel->setHeaderData(0, Qt::Horizontal, QObject::tr("Identity"));
-  m_tableModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Type"));
-  m_tableModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Value"));
-
-  ui->profileTable->setModel(m_tableModel);
-  ui->profileTable->setColumnHidden(0, true);
-  ui->profileTable->show();
-}
-
-#if WAF
-#include "profileeditor.moc"
-#include "profileeditor.cpp.moc"
-#endif
diff --git a/src/profileeditor.h b/src/profileeditor.h
deleted file mode 100644
index e36a695..0000000
--- a/src/profileeditor.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef PROFILEEDITOR_H
-#define PROFILEEDITOR_H
-
-#include <QDialog>
-#include <QtSql/QSqlTableModel>
-
-#ifndef Q_MOC_RUN
-#include "contact-manager.h"
-#include <ndn-cpp-dev/security/key-chain.hpp>
-#endif
-
-namespace Ui {
-class ProfileEditor;
-}
-
-class ProfileEditor : public QDialog
-{
-    Q_OBJECT
-
-public:
-  explicit ProfileEditor(ndn::shared_ptr<chronos::ContactManager> contactManager, 
-                         QWidget *parent = 0);
-  
-  ~ProfileEditor();
-
-  void
-  setCurrentIdentity(const ndn::Name& name)
-  { m_currentIdentity = name; }
-  
-private slots:
-  void
-  onAddClicked();
-
-  void
-  onDeleteClicked();
-
-  void
-  onOkClicked();
-
-  void
-  onGetClicked();
-
-signals:
-  void
-  noKeyOrCert(const QString&);
-
-private:
-  Ui::ProfileEditor *ui;
-  QSqlTableModel* m_tableModel;
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-  ndn::shared_ptr<ndn::KeyChain> m_keyChain;
-  ndn::Name m_currentIdentity;
-};
-
-#endif // PROFILEEDITOR_H
diff --git a/src/profileeditor.ui b/src/profileeditor.ui
deleted file mode 100644
index f3bdafd..0000000
--- a/src/profileeditor.ui
+++ /dev/null
@@ -1,114 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ProfileEditor</class>
- <widget class="QDialog" name="ProfileEditor">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>400</width>
-    <height>500</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Profile Editor</string>
-  </property>
-  <widget class="QWidget" name="">
-   <property name="geometry">
-    <rect>
-     <x>11</x>
-     <y>10</y>
-     <width>381</width>
-     <height>491</height>
-    </rect>
-   </property>
-   <layout class="QVBoxLayout" name="profileEditorLayout" stretch="1,20,1">
-    <item>
-     <layout class="QHBoxLayout" name="identityLayout" stretch="1,5,1">
-      <item>
-       <widget class="QLabel" name="identityLabel">
-        <property name="font">
-         <font>
-          <weight>75</weight>
-          <bold>true</bold>
-         </font>
-        </property>
-        <property name="text">
-         <string>Identity:</string>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QLineEdit" name="identityInput"/>
-      </item>
-      <item>
-       <widget class="QPushButton" name="getButton">
-        <property name="text">
-         <string>Get Profile</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-    <item>
-     <widget class="QTableView" name="profileTable">
-      <attribute name="horizontalHeaderCascadingSectionResizes">
-       <bool>false</bool>
-      </attribute>
-      <attribute name="horizontalHeaderDefaultSectionSize">
-       <number>100</number>
-      </attribute>
-      <attribute name="horizontalHeaderShowSortIndicator" stdset="0">
-       <bool>true</bool>
-      </attribute>
-      <attribute name="horizontalHeaderStretchLastSection">
-       <bool>true</bool>
-      </attribute>
-      <attribute name="verticalHeaderVisible">
-       <bool>true</bool>
-      </attribute>
-     </widget>
-    </item>
-    <item>
-     <layout class="QHBoxLayout" name="buttonLayout" stretch="1,1,1">
-      <item>
-       <widget class="QPushButton" name="addRowButton">
-        <property name="text">
-         <string>Add</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="deleteRowButton">
-        <property name="text">
-         <string>Delete</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-      <item>
-       <widget class="QPushButton" name="okButton">
-        <property name="text">
-         <string>OK</string>
-        </property>
-        <property name="autoDefault">
-         <bool>false</bool>
-        </property>
-       </widget>
-      </item>
-     </layout>
-    </item>
-   </layout>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/set-alias-dialog.cpp b/src/set-alias-dialog.cpp
new file mode 100644
index 0000000..7327c1b
--- /dev/null
+++ b/src/set-alias-dialog.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "set-alias-dialog.h"
+#include "ui_set-alias-dialog.h"
+
+
+using namespace ndn;
+using namespace std;
+
+SetAliasDialog::SetAliasDialog(QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::SetAliasDialog)
+{
+    ui->setupUi(this);
+
+    connect(ui->okButton, SIGNAL(clicked()),
+	    this, SLOT(onOkClicked()));
+    connect(ui->cancelButton, SIGNAL(clicked()),
+	    this, SLOT(onCancelClicked()));
+}
+
+SetAliasDialog::~SetAliasDialog()
+{
+    delete ui;
+}
+
+void
+SetAliasDialog::onOkClicked()
+{
+  emit aliasChanged(m_targetIdentity, ui->aliasInput->text());
+  this->close();
+}
+
+void
+SetAliasDialog::onCancelClicked()
+{ 
+  this->close(); 
+}
+
+void 
+SetAliasDialog::setTargetIdentity(const QString& targetIdentity, const QString& alias)
+{ 
+  m_targetIdentity = targetIdentity; 
+  QString msg = QString("Set alias for %1:").arg(targetIdentity);
+  ui->introLabel->setText(msg);
+  ui->aliasInput->setText(alias);
+}
+
+
+#if WAF
+#include "set-alias-dialog.moc"
+#include "set-alias-dialog.cpp.moc"
+#endif
diff --git a/src/setaliasdialog.h b/src/set-alias-dialog.h
similarity index 69%
rename from src/setaliasdialog.h
rename to src/set-alias-dialog.h
index 2358425..777b2c2 100644
--- a/src/setaliasdialog.h
+++ b/src/set-alias-dialog.h
@@ -14,7 +14,7 @@
 #include <QDialog>
 
 #ifndef Q_MOC_RUN
-#include "contact-manager.h"
+#include <ndn-cpp-dev/name.hpp>
 #endif
 
 namespace Ui {
@@ -26,16 +26,17 @@
   Q_OBJECT
 
 public:
-  explicit SetAliasDialog(ndn::shared_ptr<chronos::ContactManager> contactManager,
-			  QWidget *parent = 0);
+  explicit 
+  SetAliasDialog(QWidget *parent = 0);
+
   ~SetAliasDialog();
 
   void
-  setTargetIdentity(const std::string& name);
+  setTargetIdentity(const QString& targetIdentity, const QString& alias);
 
 signals:
   void
-  aliasChanged();
+  aliasChanged(const QString& identity, const QString& alias);
 
 private slots:
   void
@@ -46,8 +47,7 @@
 
 private:
   Ui::SetAliasDialog *ui;
-  ndn::shared_ptr<chronos::ContactManager> m_contactManager;
-  std::string m_target;
+  QString m_targetIdentity;
 };
 
 #endif // SETALIASDIALOG_H
diff --git a/src/set-alias-dialog.ui b/src/set-alias-dialog.ui
new file mode 100644
index 0000000..df7f7a1
--- /dev/null
+++ b/src/set-alias-dialog.ui
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SetAliasDialog</class>
+ <widget class="QDialog" name="SetAliasDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>150</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout" stretch="2,1,1">
+     <item>
+      <widget class="QLabel" name="introLabel">
+       <property name="text">
+        <string>TextLabel</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+       </property>
+       <property name="wordWrap">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLineEdit" name="aliasInput"/>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,1">
+       <property name="spacing">
+        <number>-1</number>
+       </property>
+       <item>
+        <widget class="QPushButton" name="cancelButton">
+         <property name="text">
+          <string>Cancel</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <spacer name="horizontalSpacer">
+         <property name="orientation">
+          <enum>Qt::Horizontal</enum>
+         </property>
+         <property name="sizeHint" stdset="0">
+          <size>
+           <width>40</width>
+           <height>20</height>
+          </size>
+         </property>
+        </spacer>
+       </item>
+       <item>
+        <widget class="QPushButton" name="okButton">
+         <property name="text">
+          <string>OK</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/setaliasdialog.cpp b/src/setaliasdialog.cpp
deleted file mode 100644
index 553b15c..0000000
--- a/src/setaliasdialog.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "setaliasdialog.h"
-#include "ui_setaliasdialog.h"
-
-
-using namespace ndn;
-using namespace std;
-
-SetAliasDialog::SetAliasDialog(shared_ptr<chronos::ContactManager> contactManager,
-			       QWidget *parent) 
-  : QDialog(parent)
-  , ui(new Ui::SetAliasDialog)
-  , m_contactManager(contactManager)
-{
-    ui->setupUi(this);
-
-    connect(ui->okButton, SIGNAL(clicked()),
-	    this, SLOT(onOkClicked()));
-    connect(ui->cancelButton, SIGNAL(clicked()),
-	    this, SLOT(onCancelClicked()));
-}
-
-SetAliasDialog::~SetAliasDialog()
-{
-    delete ui;
-}
-
-void
-SetAliasDialog::onOkClicked()
-{
-  QString text = ui->aliasInput->text();
-  string alias = text.toStdString();
-  
-  m_contactManager->getContactStorage()->updateAlias(Name(m_target), alias);
-
-  emit aliasChanged();
-
-  this->close();
-}
-
-void
-SetAliasDialog::onCancelClicked()
-{ this->close(); }
-
-void 
-SetAliasDialog::setTargetIdentity(const string& name)
-{ 
-  m_target = name; 
-  string msg("Set alias for ");
-  msg.append(name).append(":");
-  ui->introLabel->setText(QString::fromStdString(msg));
-  ui->aliasInput->clear();
-}
-
-
-#if WAF
-#include "setaliasdialog.moc"
-#include "setaliasdialog.cpp.moc"
-#endif
diff --git a/src/setaliasdialog.ui b/src/setaliasdialog.ui
deleted file mode 100644
index 3beeb3a..0000000
--- a/src/setaliasdialog.ui
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SetAliasDialog</class>
- <widget class="QDialog" name="SetAliasDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>300</width>
-    <height>150</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <widget class="QLineEdit" name="aliasInput">
-   <property name="geometry">
-    <rect>
-     <x>20</x>
-     <y>60</y>
-     <width>260</width>
-     <height>21</height>
-    </rect>
-   </property>
-  </widget>
-  <widget class="QPushButton" name="okButton">
-   <property name="geometry">
-    <rect>
-     <x>180</x>
-     <y>100</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>OK</string>
-   </property>
-  </widget>
-  <widget class="QPushButton" name="cancelButton">
-   <property name="geometry">
-    <rect>
-     <x>20</x>
-     <y>100</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>Cancel</string>
-   </property>
-  </widget>
-  <widget class="QLabel" name="introLabel">
-   <property name="geometry">
-    <rect>
-     <x>20</x>
-     <y>20</y>
-     <width>260</width>
-     <height>30</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>TextLabel</string>
-   </property>
-   <property name="alignment">
-    <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
-   </property>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/setting-dialog.cpp b/src/setting-dialog.cpp
new file mode 100644
index 0000000..d0f98ae
--- /dev/null
+++ b/src/setting-dialog.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "setting-dialog.h"
+#include "ui_setting-dialog.h"
+
+SettingDialog::SettingDialog(QWidget *parent)
+  : QDialog(parent)
+  , ui(new Ui::SettingDialog)
+{
+  ui->setupUi(this);
+  
+  connect(ui->saveButton, SIGNAL(clicked()),
+          this, SLOT(onSaveClicked()));
+  connect(ui->cancelButton, SIGNAL(clicked()),
+          this, SLOT(onCancelClicked()));
+}
+
+SettingDialog::~SettingDialog()
+{
+  delete ui;
+}
+
+void
+SettingDialog::setNick(const QString& nick)
+{
+  m_nick = nick;
+  ui->nickLine->setText(m_nick);
+}
+
+void
+SettingDialog::onIdentityUpdated(const QString& identity)
+{
+  m_identity = identity;
+  ui->identityLine->setText(m_identity);
+}
+
+void
+SettingDialog::onSaveClicked()
+{
+  QString identity = ui->identityLine->text();
+  QString nick = ui->nickLine->text();
+
+  if(identity != m_identity)
+    {
+      m_identity = identity;
+      emit identityUpdated(identity);
+    }
+  if(nick != m_nick)
+    {
+      m_nick = nick;
+      emit nickUpdated(nick);
+    }
+
+  this->close();
+}
+
+void
+SettingDialog::onCancelClicked()
+{
+  this->close();
+}
+
+
+#if WAF
+#include "setting-dialog.moc"
+#include "setting-dialog.cpp.moc"
+#endif
diff --git a/src/setting-dialog.h b/src/setting-dialog.h
new file mode 100644
index 0000000..b38c376
--- /dev/null
+++ b/src/setting-dialog.h
@@ -0,0 +1,60 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef SETTING_DIALOG_H
+#define SETTING_DIALOG_H
+
+#include <QDialog>
+
+#ifndef Q_MOC_RUN
+#endif
+
+namespace Ui {
+class SettingDialog;
+}
+
+class SettingDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit 
+  SettingDialog(QWidget *parent = 0);
+
+  ~SettingDialog();
+
+  void
+  setNick(const QString& nick);
+
+signals:
+  void
+  identityUpdated(const QString& identity);
+
+  void
+  nickUpdated(const QString& nick);
+
+public slots:
+  void
+  onIdentityUpdated(const QString& identity);
+
+private slots:
+  void
+  onSaveClicked();
+
+  void
+  onCancelClicked();
+
+private:
+  Ui::SettingDialog *ui;
+  QString m_identity;
+  QString m_nick;
+};
+
+#endif // SETTING_DIALOG_H
diff --git a/src/setting-dialog.ui b/src/setting-dialog.ui
new file mode 100644
index 0000000..f3b4d86
--- /dev/null
+++ b/src/setting-dialog.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingDialog</class>
+ <widget class="QDialog" name="SettingDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>124</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QVBoxLayout" name="verticalLayout">
+     <item>
+      <layout class="QHBoxLayout" name="identityLayout" stretch="3,7">
+       <item>
+        <widget class="QLabel" name="identityLabel">
+         <property name="font">
+          <font>
+           <weight>75</weight>
+           <bold>true</bold>
+          </font>
+         </property>
+         <property name="text">
+          <string>Identity:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLineEdit" name="identityLine"/>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="nickLayout" stretch="3,7">
+       <item>
+        <widget class="QLabel" name="nickLabel">
+         <property name="font">
+          <font>
+           <weight>75</weight>
+           <bold>true</bold>
+          </font>
+         </property>
+         <property name="text">
+          <string>nick:</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QLineEdit" name="nickLine"/>
+       </item>
+      </layout>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="buttonLayout">
+       <item>
+        <widget class="QPushButton" name="cancelButton">
+         <property name="text">
+          <string>Cancel</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="saveButton">
+         <property name="text">
+          <string>Save</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/settingdialog.cpp b/src/settingdialog.cpp
deleted file mode 100644
index ed9a1bd..0000000
--- a/src/settingdialog.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "settingdialog.h"
-#include "ui_settingdialog.h"
-
-using namespace std;
-
-SettingDialog::SettingDialog(QWidget *parent) :
-    QDialog(parent),
-    ui(new Ui::SettingDialog)
-{
-    ui->setupUi(this);
-
-    connect(ui->okButton, SIGNAL(clicked()),
-            this, SLOT(onOkClicked()));
-}
-
-SettingDialog::~SettingDialog()
-{
-    delete ui;
-}
-
-void
-SettingDialog::setIdentity(const std::string& identity,
-                           const std::string& nickName)
-{ 
-  m_identity = identity;
-  ui->identityLine->setText(QString::fromStdString(m_identity));
-  m_nickName = nickName;
-  ui->nickLine->setText(QString::fromStdString(m_nickName));
-}
-
-void
-SettingDialog::onOkClicked()
-{
-  QString qIdentity = ui->identityLine->text();
-  string identity = qIdentity.toStdString();
-  QString qNick = ui->nickLine->text();
-  string nick = qNick.toStdString();
-
-  if(identity != m_identity || nick != m_nickName)
-    {
-      m_identity = identity;
-      m_nickName = nick;
-      emit identitySet(qIdentity, qNick);
-    }
-  this->close();
-}
-
-
-#if WAF
-#include "settingdialog.moc"
-#include "settingdialog.cpp.moc"
-#endif
diff --git a/src/settingdialog.h b/src/settingdialog.h
deleted file mode 100644
index 9ee6865..0000000
--- a/src/settingdialog.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef SETTINGDIALOG_H
-#define SETTINGDIALOG_H
-
-#include <QDialog>
-
-namespace Ui {
-class SettingDialog;
-}
-
-class SettingDialog : public QDialog
-{
-  Q_OBJECT
-
-public:
-  explicit SettingDialog(QWidget *parent = 0);
-  ~SettingDialog();
-
-  void
-  setIdentity(const std::string& identity,
-              const std::string& nickName);
-
-signals:
-  void
-  identitySet(const QString& identity,
-              const QString& nickName);
-
-private slots:
-  void
-  onOkClicked();
-
-private:
-  Ui::SettingDialog *ui;
-  std::string m_identity;
-  std::string m_nickName;
-};
-
-#endif // SETTINGDIALOG_H
diff --git a/src/settingdialog.ui b/src/settingdialog.ui
deleted file mode 100644
index 271ef23..0000000
--- a/src/settingdialog.ui
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>SettingDialog</class>
- <widget class="QDialog" name="SettingDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>300</width>
-    <height>150</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <widget class="QPushButton" name="okButton">
-   <property name="geometry">
-    <rect>
-     <x>100</x>
-     <y>110</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>OK</string>
-   </property>
-  </widget>
-  <widget class="QLabel" name="msgLabel">
-   <property name="geometry">
-    <rect>
-     <x>10</x>
-     <y>10</y>
-     <width>150</width>
-     <height>16</height>
-    </rect>
-   </property>
-   <property name="font">
-    <font>
-     <weight>75</weight>
-     <bold>true</bold>
-    </font>
-   </property>
-   <property name="text">
-    <string>Current Identity:</string>
-   </property>
-  </widget>
-  <widget class="QLineEdit" name="identityLine">
-   <property name="geometry">
-    <rect>
-     <x>10</x>
-     <y>30</y>
-     <width>280</width>
-     <height>21</height>
-    </rect>
-   </property>
-  </widget>
-  <widget class="QLabel" name="nickLabel">
-   <property name="geometry">
-    <rect>
-     <x>10</x>
-     <y>60</y>
-     <width>150</width>
-     <height>16</height>
-    </rect>
-   </property>
-   <property name="font">
-    <font>
-     <weight>75</weight>
-     <bold>true</bold>
-    </font>
-   </property>
-   <property name="text">
-    <string>Nick Name:</string>
-   </property>
-  </widget>
-  <widget class="QLineEdit" name="nickLine">
-   <property name="geometry">
-    <rect>
-     <x>10</x>
-     <y>80</y>
-     <width>280</width>
-     <height>21</height>
-    </rect>
-   </property>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/startchatdialog.cpp b/src/start-chat-dialog.cpp
similarity index 63%
rename from src/startchatdialog.cpp
rename to src/start-chat-dialog.cpp
index 444f9c7..e9ac1f8 100644
--- a/src/startchatdialog.cpp
+++ b/src/start-chat-dialog.cpp
@@ -8,16 +8,17 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#include "startchatdialog.h"
-#include "ui_startchatdialog.h"
+#include "start-chat-dialog.h"
+#include "ui_start-chat-dialog.h"
 
 using namespace std;
 
-StartChatDialog::StartChatDialog(QWidget *parent) :
-    QDialog(parent),
-    ui(new Ui::StartChatDialog)
+StartChatDialog::StartChatDialog(QWidget *parent) 
+  : QDialog(parent)
+  , ui(new Ui::StartChatDialog)
 {
     ui->setupUi(this);
+
     connect(ui->okButton, SIGNAL(clicked()),
 	    this, SLOT(onOkClicked()));
     connect(ui->cancelButton, SIGNAL(clicked()),
@@ -25,25 +26,32 @@
 }
 
 StartChatDialog::~StartChatDialog()
-{ delete ui; }
+{ 
+  delete ui; 
+}
 
 void
 StartChatDialog::setChatroom(const string& chatroom)
-{ ui->chatroomInput->setText(QString::fromStdString(chatroom)); }
+{ 
+  ui->chatroomInput->setText(QString::fromStdString(chatroom)); 
+}
 
 void
 StartChatDialog::onOkClicked()
 {
   QString chatroom = ui->chatroomInput->text();
-  emit chatroomConfirmed(chatroom);
+  bool secured = ui->withSecurity->isChecked();
+  emit startChatroom(chatroom, secured);
   this->close();
 }
 
 void
 StartChatDialog::onCancelClicked()
-{ this->close(); }
+{ 
+  this->close(); 
+}
 
 #if WAF
-#include "startchatdialog.moc"
-#include "startchatdialog.cpp.moc"
+#include "start-chat-dialog.moc"
+#include "start-chat-dialog.cpp.moc"
 #endif
diff --git a/src/startchatdialog.h b/src/start-chat-dialog.h
similarity index 82%
rename from src/startchatdialog.h
rename to src/start-chat-dialog.h
index 056ef9a..7aa916b 100644
--- a/src/startchatdialog.h
+++ b/src/start-chat-dialog.h
@@ -8,8 +8,8 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef STARTCHATDIALOG_H
-#define STARTCHATDIALOG_H
+#ifndef START_CHAT_DIALOG_H
+#define START_CHAT_DIALOG_H
 
 #include <QDialog>
 
@@ -35,7 +35,7 @@
 
 signals:
   void
-  chatroomConfirmed(const QString& chatroomName);
+  startChatroom(const QString& chatroomName, bool secured);
     
 private slots:
   void
@@ -48,4 +48,4 @@
   Ui::StartChatDialog *ui;
 };
 
-#endif // STARTCHATDIALOG_H
+#endif // START_CHAT_DIALOG_H
diff --git a/src/start-chat-dialog.ui b/src/start-chat-dialog.ui
new file mode 100644
index 0000000..ced5bf5
--- /dev/null
+++ b/src/start-chat-dialog.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>StartChatDialog</class>
+ <widget class="QDialog" name="StartChatDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>100</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QCheckBox" name="withSecurity">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>40</y>
+     <width>480</width>
+     <height>20</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>with security</string>
+   </property>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>10</y>
+     <width>281</width>
+     <height>23</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="chatroomLineLayout">
+    <item>
+     <widget class="QLabel" name="introLabel">
+      <property name="font">
+       <font>
+        <weight>75</weight>
+        <bold>true</bold>
+       </font>
+      </property>
+      <property name="text">
+       <string>Chatroom Name:</string>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QLineEdit" name="chatroomInput"/>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>60</y>
+     <width>281</width>
+     <height>32</height>
+    </rect>
+   </property>
+   <layout class="QHBoxLayout" name="buttonLayout" stretch="1,1">
+    <property name="spacing">
+     <number>-1</number>
+    </property>
+    <item>
+     <widget class="QPushButton" name="cancelButton">
+      <property name="text">
+       <string>Cancel</string>
+      </property>
+      <property name="autoDefault">
+       <bool>false</bool>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QPushButton" name="okButton">
+      <property name="text">
+       <string>OK</string>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/startchatdialog.ui b/src/startchatdialog.ui
deleted file mode 100644
index c6ec4d6..0000000
--- a/src/startchatdialog.ui
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>StartChatDialog</class>
- <widget class="QDialog" name="StartChatDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>300</width>
-    <height>200</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Dialog</string>
-  </property>
-  <widget class="QPushButton" name="okButton">
-   <property name="geometry">
-    <rect>
-     <x>180</x>
-     <y>150</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>OK</string>
-   </property>
-  </widget>
-  <widget class="QLineEdit" name="chatroomInput">
-   <property name="geometry">
-    <rect>
-     <x>20</x>
-     <y>70</y>
-     <width>260</width>
-     <height>21</height>
-    </rect>
-   </property>
-  </widget>
-  <widget class="QLabel" name="introLabel">
-   <property name="geometry">
-    <rect>
-     <x>20</x>
-     <y>30</y>
-     <width>260</width>
-     <height>16</height>
-    </rect>
-   </property>
-   <property name="font">
-    <font>
-     <weight>75</weight>
-     <bold>true</bold>
-    </font>
-   </property>
-   <property name="text">
-    <string>Chatroom Prefix:</string>
-   </property>
-  </widget>
-  <widget class="QPushButton" name="cancelButton">
-   <property name="geometry">
-    <rect>
-     <x>20</x>
-     <y>150</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>Cancel</string>
-   </property>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>
diff --git a/src/validator-invitation.cpp b/src/validator-invitation.cpp
index d22d55b..ec54a38 100644
--- a/src/validator-invitation.cpp
+++ b/src/validator-invitation.cpp
@@ -9,6 +9,7 @@
  */
 
 #include "validator-invitation.h"
+#include "invitation.h"
 
 #include "logging.h"
 
@@ -21,208 +22,123 @@
 
 const shared_ptr<CertificateCache> ValidatorInvitation::DefaultCertificateCache = shared_ptr<CertificateCache>();
 
-ValidatorInvitation::ValidatorInvitation(shared_ptr<Face> face,                                        
-                                         const string& chatroomName,
-                                         const Name& signingIdentity,
-                                         shared_ptr<CertificateCache> certificateCache,
-                                         int stepLimit)
-  : Validator(face)
-  , m_stepLimit(stepLimit)
-  , m_certificateCache(certificateCache)
-  , m_chatroomName(chatroomName)
-  , m_signingIdentity(signingIdentity)
+ValidatorInvitation::ValidatorInvitation()
+  : Validator()
+  , m_invitationReplyRule("^([^<CHRONOCHAT-INVITATION>]*)<CHRONOCHAT-INVITATION>", 
+                          "^([^<KEY>]*)<KEY>(<>*)[<dsk-.*><ksk-.*>]<ID-CERT>$", 
+                          "==", "\\1", "\\1\\2", true)
+  , m_invitationInterestRule("^[^<CHRONOCHAT-INVITATION>]*<CHRONOCHAT-INVITATION><>{6}$")
+  , m_innerKeyRegex("^([^<KEY>]*)<KEY>(<>*)[<dsk-.*><ksk-.*>]<ID-CERT><>$", "\\1\\2")
 {
-  m_invitationRule = make_shared<SecRuleRelative>("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", 
-                                                  "^([^<KEY>]*)<KEY>(<>*)[<dsk-.*><ksk-.*>]<ID-CERT>$", 
-                                                  "==", "\\1", "\\1\\2", true);
-
-  m_dskRule = make_shared<SecRuleRelative>("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT><>$", 
-                                           "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
-                                           "==", "\\1", "\\1\\2", true);
-} 
+}
 
 void
-ValidatorInvitation::checkPolicy (const shared_ptr<const Data>& data, 
+ValidatorInvitation::checkPolicy (const Data& data, 
                                   int stepCount, 
                                   const OnDataValidated& onValidated, 
                                   const OnDataValidationFailed& onValidationFailed,
                                   vector<shared_ptr<ValidationRequest> >& nextSteps)
 {
-  if(m_stepLimit == stepCount)
+  try
     {
-      _LOG_DEBUG("reach the maximum steps of verification");
-      onValidationFailed(data);
-      return;
+      SignatureSha256WithRsa sig(data.getSignature());    
+      const Name & keyLocatorName = sig.getKeyLocator().getName();
+      
+      if(!m_invitationReplyRule.satisfy(data.getName(), keyLocatorName))
+        return onValidationFailed(data.shared_from_this(),
+                                  "Does not comply with the invitation rule: "
+                                  + data.getName().toUri() + " signed by: "
+                                  + keyLocatorName.toUri());
+
+      Data innerData;
+      innerData.wireDecode(data.getContent().blockFromValue());
+      
+      return internalCheck(data.wireEncode().wire(), 
+                           data.wireEncode().size(),
+                           sig,
+                           innerData,
+                           bind(onValidated, data.shared_from_this()), 
+                           bind(onValidationFailed, data.shared_from_this(), _1));
     }
-
-   try{
-    SignatureSha256WithRsa sig(data->getSignature());    
-    const Name & keyLocatorName = sig.getKeyLocator().getName();
-    const uint8_t* buf = data->wireEncode().wire();
-    const size_t size = data->wireEncode().size();
-
-    if(m_invitationRule->satisfy(data->getName(), keyLocatorName))
-      processSignature(buf, size,
-                       sig, keyLocatorName, 
-                       bind(onValidated, data),
-                       bind(onValidationFailed, data),
-                       stepCount,
-                       nextSteps);
-
-    if(m_dskRule->satisfy(data->getName(), keyLocatorName))
-      processFinalSignature(buf, size,
-                            sig, keyLocatorName,
-                            bind(onValidated, data),
-                            bind(onValidationFailed, data));
-
-  }catch(...){
-    onValidationFailed(data);
-    return;
-  }
+   catch(SignatureSha256WithRsa::Error &e)
+     {
+       return onValidationFailed(data.shared_from_this(), 
+                                 "Not SignatureSha256WithRsa signature: " + data.getName().toUri());
+     }
 }
 
 void
-ValidatorInvitation::checkPolicy (const shared_ptr<const Interest>& interest, 
+ValidatorInvitation::checkPolicy (const Interest& interest, 
                                   int stepCount, 
                                   const OnInterestValidated& onValidated, 
                                   const OnInterestValidationFailed& onValidationFailed,
                                   vector<shared_ptr<ValidationRequest> >& nextSteps)
 {
-  try{    
-    Name interestName  = interest->getName();
-
-    Block signatureBlock = interestName.get(-1).blockFromValue();
-    Block signatureInfo = interestName.get(-2).blockFromValue();
-    Signature signature(signatureInfo, signatureBlock);
-    
-    SignatureSha256WithRsa sig(signature);
-    const Name & keyLocatorName = sig.getKeyLocator().getName();
-
-    Name signedName = interestName.getPrefix(-1);
-    Buffer signedBlob = Buffer(signedName.wireEncode().value(), signedName.wireEncode().value_size());
-
-    processSignature(signedBlob.buf(), signedBlob.size(),
-                     sig, keyLocatorName, 
-                     bind(onValidated, interest),
-                     bind(onValidationFailed, interest),
-                     stepCount,
-                     nextSteps);
-
-  }catch(...){
-    onValidationFailed(interest);
-    return;
-  }
-
-}
-
-void
-ValidatorInvitation::processSignature (const uint8_t* buf, 
-                                       const size_t size,
-                                       const SignatureSha256WithRsa& signature,
-                                       const Name& keyLocatorName,
-                                       const OnValidated& onValidated, 
-                                       const OnValidationFailed& onValidationFailed,
-                                       int stepCount,
-                                       vector<shared_ptr<ValidationRequest> >& nextSteps)
-{
-  try{
-    Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
-    
-    if(m_trustAnchors.find(keyName) != m_trustAnchors.end())
-      {
-        if(Validator::verifySignature(buf, size, signature, m_trustAnchors[keyName]))
-          onValidated();
-        else
-          onValidationFailed();
-        return;
-      }
-
-    if(static_cast<bool>(m_certificateCache))
-      {
-        shared_ptr<const IdentityCertificate> trustedCert = m_certificateCache->getCertificate(keyLocatorName);
-        if(static_cast<bool>(trustedCert)){
-          if(Validator::verifySignature(buf, size, signature, trustedCert->getPublicKeyInfo()))
-            onValidated();
-          else
-            onValidationFailed();
-          return;
-        }
-      }
-    
-    OnDataValidated onKeyLocatorValidated = 
-      bind(&ValidatorInvitation::onDskKeyLocatorValidated, 
-           this, _1, buf, size, signature, onValidated, onValidationFailed);
-    
-    OnDataValidationFailed onKeyLocatorValidationFailed = 
-      bind(&ValidatorInvitation::onDskKeyLocatorValidationFailed, 
-           this, _1, onValidationFailed);
-    
-    Interest interest(keyLocatorName);
-    interest.setMustBeFresh(true);
-    
-    shared_ptr<ValidationRequest> nextStep = make_shared<ValidationRequest>
-      (interest, onKeyLocatorValidated, onKeyLocatorValidationFailed, 0, stepCount + 1);
-
-    nextSteps.push_back(nextStep);
-    return;
-  }catch(...){
-    onValidationFailed();
-    return;
-  }
-}
- 
-void
-ValidatorInvitation::processFinalSignature (const uint8_t* buf, 
-                                            const size_t size,
-                                            const SignatureSha256WithRsa& signature,
-                                            const Name& keyLocatorName,
-                                            const OnValidated& onValidated, 
-                                            const OnValidationFailed& onValidationFailed)
-{
-  try{
-    Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
-
-    if(m_trustAnchors.end() != m_trustAnchors.find(keyName) && Validator::verifySignature(buf, size, signature, m_trustAnchors[keyName]))
-      onValidated();
-    else
-      onValidationFailed();
-    return;
-  }catch(...){
-    onValidationFailed();
-    return;
-  }
-}
-
-
-void 
-ValidatorInvitation::onDskKeyLocatorValidated(const shared_ptr<const Data>& certData, 
-                                              const uint8_t* buf,
-                                              const size_t size,
-                                              const SignatureSha256WithRsa& signature,
-                                              const OnValidated& onValidated, 
-                                              const OnValidationFailed& onValidationFailed)
-{
-  shared_ptr<IdentityCertificate> certificate = make_shared<IdentityCertificate>(*certData);
-
-  if(!certificate->isTooLate() && !certificate->isTooEarly())
+  try
     {
-      Name certName = certificate->getName().getPrefix(-1);
-      m_dskCertificates[certName] = certificate;
+      Name interestName  = interest.getName();
+      
+      if(!m_invitationInterestRule.match(interestName))
+        return onValidationFailed(interest.shared_from_this(), 
+                                  "Invalid interest name: " +  interest.getName().toUri());
 
-      if(Validator::verifySignature(buf, size, signature, certificate->getPublicKeyInfo()))
-        {
-          onValidated();
-          return;
-        }
+      Name signedName = interestName.getPrefix(-1);
+      Buffer signedBlob = Buffer(signedName.wireEncode().value(), signedName.wireEncode().value_size());
+
+      Block signatureBlock = interestName.get(Invitation::SIGNATURE).blockFromValue();
+      Block signatureInfo = interestName.get(Invitation::KEY_LOCATOR).blockFromValue();
+      Signature signature(signatureInfo, signatureBlock);
+      SignatureSha256WithRsa sig(signature);
+
+      Data innerData;
+      innerData.wireDecode(interestName.get(Invitation::INVITER_CERT).blockFromValue());
+
+      return internalCheck(signedBlob.buf(), 
+                           signedBlob.size(),
+                           sig,
+                           innerData,
+                           bind(onValidated, interest.shared_from_this()), 
+                           bind(onValidationFailed, interest.shared_from_this(), _1));
     }
-
-  onValidationFailed();
-  return;
+  catch(SignatureSha256WithRsa::Error& e)
+    {
+      return onValidationFailed(interest.shared_from_this(), 
+                                "Not SignatureSha256WithRsa signature: " + interest.getName().toUri());
+    }
 }
 
 void
-ValidatorInvitation::onDskKeyLocatorValidationFailed(const shared_ptr<const Data>& certData, 
-                                                     const OnValidationFailed& onValidationFailed)
-{ onValidationFailed(); }
+ValidatorInvitation::internalCheck(const uint8_t* buf, size_t size,
+                                   const SignatureSha256WithRsa& sig,
+                                   const Data& innerData,
+                                   const OnValidated& onValidated, 
+                                   const OnValidationFailed& onValidationFailed)
+{
+  try
+    {
+      const Name & keyLocatorName = sig.getKeyLocator().getName();
+      Name signingKeyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
+      
+      if(m_trustAnchors.find(signingKeyName) == m_trustAnchors.end())
+        return onValidationFailed("Cannot reach any trust anchor");
+
+      if(!Validator::verifySignature(buf, size, sig, m_trustAnchors[signingKeyName]))
+        return onValidationFailed("Cannot verify interest signature");
+
+      if(!Validator::verifySignature(innerData, m_trustAnchors[signingKeyName]))
+        return onValidationFailed("Cannot verify interest signature");
+
+      if(!m_innerKeyRegex.match(innerData.getName())
+          || m_innerKeyRegex.expand() != signingKeyName.getPrefix(-1))
+         return onValidationFailed("Inner certificate does not comply with the rule");
+
+      return onValidated();
+    }
+  catch(KeyLocator::Error& e)
+    {
+      return onValidationFailed("Key Locator is not a name");
+    }
+}
+
 
 }//chronos
diff --git a/src/validator-invitation.h b/src/validator-invitation.h
index ede1799..cb22d65 100644
--- a/src/validator-invitation.h
+++ b/src/validator-invitation.h
@@ -22,7 +22,7 @@
 
 class ValidatorInvitation : public ndn::Validator
 {
-  typedef ndn::function< void () > OnValidationFailed;
+  typedef ndn::function< void (const std::string&) > OnValidationFailed;
   typedef ndn::function< void () > OnValidated;
 
 public:
@@ -30,101 +30,59 @@
 
   static const ndn::shared_ptr<ndn::CertificateCache> DefaultCertificateCache;
 
-  ValidatorInvitation(ndn::shared_ptr<ndn::Face> face,                      
-                      const std::string& chatroomName,
-                      const ndn::Name& signingIdentity,
-                      ndn::shared_ptr<ndn::CertificateCache> certificateCache = DefaultCertificateCache,
-                      int stepLimit = 10);
+  ValidatorInvitation();
   
   virtual
   ~ValidatorInvitation() {};
 
   void
-  addTrustAnchor(const EndorseCertificate& cert)
-  { m_trustAnchors[cert.getPublicKeyName()] = cert.getPublicKeyInfo(); }
+  addTrustAnchor(const ndn::Name& keyName, const ndn::PublicKey& key)
+  { 
+    m_trustAnchors[keyName] = key; 
+  }
 
   void
   removeTrustAnchor(const ndn::Name& keyName)
-  { m_trustAnchors.erase(keyName); }
-
-  ndn::shared_ptr<ndn::IdentityCertificate> 
-  getValidatedDskCertificate(const ndn::Name& certName)
-  {
-    ValidatedCertifcates::iterator it = m_dskCertificates.find(certName);
-    if(m_dskCertificates.end() != it)
-      return it->second;
-    else
-      return ndn::shared_ptr<ndn::IdentityCertificate>();
+  { 
+    m_trustAnchors.erase(keyName); 
   }
 
-
+  void
+  cleanTrustAnchor()
+  {
+    m_trustAnchors.clear();
+  }
+  
 protected:
   void
-  checkPolicy (const ndn::shared_ptr<const ndn::Data>& data, 
-               int stepCount, 
-               const ndn::OnDataValidated& onValidated, 
-               const ndn::OnDataValidationFailed& onValidationFailed,
-               std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
-
-  void
-  checkPolicy (const ndn::shared_ptr<const ndn::Interest>& interest, 
-               int stepCount, 
-               const ndn::OnInterestValidated& onValidated, 
-               const ndn::OnInterestValidationFailed& onValidationFailed,
-               std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
-
-private:
-  void 
-  onDskKeyLocatorValidated(const ndn::shared_ptr<const ndn::Data>& certData, 
-                           const uint8_t* buf,
-                           const size_t size,
-                           const ndn::SignatureSha256WithRsa& signature,
-                           const OnValidated& onValidated, 
-                           const OnValidationFailed& onValidationFailed);
+  checkPolicy(const ndn::Data& data, 
+              int stepCount, 
+              const ndn::OnDataValidated& onValidated, 
+              const ndn::OnDataValidationFailed& onValidationFailed,
+              std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
   
   void
-  onDskKeyLocatorValidationFailed(const ndn::shared_ptr<const ndn::Data>& certData, 
-                                  const OnValidationFailed& onValidationFailed);
-
-  void
-  processSignature (const uint8_t* buf, 
-                    const size_t size,
-                    const ndn::SignatureSha256WithRsa& signature,
-                    const ndn::Name& keyLocatorName,
-                    const OnValidated& onValidated, 
-                    const OnValidationFailed& onValidationFailed,
-                    int stepCount,
-                    std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
-
-  void
-  processFinalSignature (const uint8_t* buf, 
-                         const size_t size,
-                         const ndn::SignatureSha256WithRsa& signature,
-                         const ndn::Name& keyLocatorName,
-                         const OnValidated& onValidated, 
-                         const OnValidationFailed& onValidationFailed);
+  checkPolicy(const ndn::Interest& interest, 
+              int stepCount, 
+              const ndn::OnInterestValidated& onValidated, 
+              const ndn::OnInterestValidationFailed& onValidationFailed,
+              std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps);
 
 private:
+  void
+  internalCheck(const uint8_t* buf, size_t size,
+                const ndn::SignatureSha256WithRsa& sig,
+                const ndn::Data& innerData,
+                const OnValidated& onValidated, 
+                const OnValidationFailed& onValidationFailed);
 
+private:
   typedef std::map<ndn::Name, ndn::PublicKey> TrustAnchors;
-  typedef std::map<ndn::Name, ndn::shared_ptr<ndn::IdentityCertificate> > ValidatedCertifcates;
 
-  int m_stepLimit;
-  ndn::shared_ptr<ndn::CertificateCache> m_certificateCache;
-
-  std::string m_chatroomName;
-  ndn::Name m_signingIdentity;
-
-  ndn::shared_ptr<ndn::SecRuleRelative> m_invitationRule;
-  ndn::shared_ptr<ndn::SecRuleRelative> m_dskRule;
-
-  ndn::shared_ptr<ndn::Regex> m_kskRegex;
-  ndn::shared_ptr<ndn::Regex> m_keyNameRegex;
-
+  ndn::SecRuleRelative m_invitationReplyRule;
+  ndn::Regex m_invitationInterestRule;
+  ndn::Regex m_innerKeyRegex;
   TrustAnchors m_trustAnchors;
-
-  ValidatedCertifcates m_dskCertificates;
-
 };
 
 }//chronos
diff --git a/src/validator-panel.cpp b/src/validator-panel.cpp
index 5622bc6..8de4bb6 100644
--- a/src/validator-panel.cpp
+++ b/src/validator-panel.cpp
@@ -44,32 +44,40 @@
   if(m_stepLimit == stepCount)
     {
       _LOG_ERROR("Reach the maximum steps of verification!");
-      onValidationFailed(data.shared_from_this());
+      onValidationFailed(data.shared_from_this(), 
+                         "Reach maximum validation steps: " + data.getName().toUri());
       return;
     }
 
-  try{
-    SignatureSha256WithRsa sig(data.getSignature());    
-    const Name& keyLocatorName = sig.getKeyLocator().getName();
+  try
+    {
+      SignatureSha256WithRsa sig(data.getSignature());
+      const Name& keyLocatorName = sig.getKeyLocator().getName();
 
-    if(m_endorseeRule->satisfy(data.getName(), keyLocatorName))
-      {
-        Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
+      if(m_endorseeRule->satisfy(data.getName(), keyLocatorName))
+        {
+          Name keyName = IdentityCertificate::certificateNameToPublicKeyName(keyLocatorName);
 
-        if(m_trustAnchors.end() != m_trustAnchors.find(keyName) && Validator::verifySignature(data, sig, m_trustAnchors[keyName]))
-          onValidated(data.shared_from_this());
-        else
-          onValidationFailed(data.shared_from_this());
-      }
-    else
-      onValidationFailed(data.shared_from_this());
+          if(m_trustAnchors.end() != m_trustAnchors.find(keyName) && Validator::verifySignature(data, sig, m_trustAnchors[keyName]))
+            onValidated(data.shared_from_this());
+          else
+            onValidationFailed(data.shared_from_this(), "Cannot verify signature:" + data.getName().toUri());
+        }
+      else
+        onValidationFailed(data.shared_from_this(), "Does not satisfy rule: " + data.getName().toUri());
 
-    return;
-
-  }catch(...){
-    onValidationFailed(data.shared_from_this());
-    return;
-  }  
+      return;
+    }
+  catch(SignatureSha256WithRsa::Error &e)
+    {
+      return onValidationFailed(data.shared_from_this(), 
+                                "Not SignatureSha256WithRsa signature: " + data.getName().toUri());
+    }
+  catch(KeyLocator::Error &e)
+    {
+      return onValidationFailed(data.shared_from_this(),
+                                "Key Locator is not a name: " + data.getName().toUri());
+    }
 }
 
 }//chronos
diff --git a/src/validator-panel.h b/src/validator-panel.h
index 2bcc226..3b5f670 100644
--- a/src/validator-panel.h
+++ b/src/validator-panel.h
@@ -52,7 +52,10 @@
                const ndn::OnInterestValidated& onValidated, 
                const ndn::OnInterestValidationFailed& onValidationFailed,
                std::vector<ndn::shared_ptr<ndn::ValidationRequest> >& nextSteps)
-  { onValidationFailed(interest.shared_from_this()); }
+  {
+    onValidationFailed(interest.shared_from_this(),
+                       "No rules for interest.");
+  }
 
 private:
   int m_stepLimit;
@@ -62,11 +65,11 @@
   
 };
 
-void
+inline void
 ValidatorPanel::addTrustAnchor(const EndorseCertificate& cert)
 { m_trustAnchors[cert.getPublicKeyName()] = cert.getPublicKeyInfo(); }
 
-void 
+inline void 
 ValidatorPanel::removeTrustAnchor(const ndn::Name& keyName)
 { m_trustAnchors.erase(keyName); }
 
diff --git a/src/warningdialog.cpp b/src/warningdialog.cpp
deleted file mode 100644
index 6dcae60..0000000
--- a/src/warningdialog.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "warningdialog.h"
-#include "ui_warningdialog.h"
-
-using namespace std;
-
-WarningDialog::WarningDialog(QWidget *parent) :
-    QDialog(parent),
-    ui(new Ui::WarningDialog)
-{
-  ui->setupUi(this);
-
-  connect(ui->okButton, SIGNAL(clicked()),
-	  this, SLOT(onOkClicked()));
-}
-
-WarningDialog::~WarningDialog()
-{
-    delete ui;
-}
-
-void
-WarningDialog::setMsg(const string& msg)
-{ ui->message->setText(QString::fromStdString(msg)); }
-
-void
-WarningDialog::onOkClicked()
-{ this->hide(); }
-
-#if WAF
-#include "warningdialog.moc"
-#include "warningdialog.cpp.moc"
-#endif
diff --git a/src/warningdialog.h b/src/warningdialog.h
deleted file mode 100644
index a2f3481..0000000
--- a/src/warningdialog.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef WARNINGDIALOG_H
-#define WARNINGDIALOG_H
-
-#include <QDialog>
-
-namespace Ui {
-class WarningDialog;
-}
-
-class WarningDialog : public QDialog
-{
-  Q_OBJECT
-
-public:
-  explicit WarningDialog(QWidget *parent = 0);
-
-  ~WarningDialog();
-                  
-  void
-  setMsg(const std::string& msg);
-
-private slots:
-  void
-  onOkClicked();
-
-private:
-  Ui::WarningDialog *ui;
-};
-
-#endif // WARNINGDIALOG_H
diff --git a/src/warningdialog.ui b/src/warningdialog.ui
deleted file mode 100644
index e67bc40..0000000
--- a/src/warningdialog.ui
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>WarningDialog</class>
- <widget class="QDialog" name="WarningDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>300</width>
-    <height>200</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Error</string>
-  </property>
-  <widget class="QLabel" name="message">
-   <property name="geometry">
-    <rect>
-     <x>30</x>
-     <y>30</y>
-     <width>240</width>
-     <height>200</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>TextLabel</string>
-   </property>
-   <property name="alignment">
-    <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
-   </property>
-  </widget>
-  <widget class="QPushButton" name="okButton">
-   <property name="geometry">
-    <rect>
-     <x>100</x>
-     <y>150</y>
-     <width>100</width>
-     <height>32</height>
-    </rect>
-   </property>
-   <property name="text">
-    <string>OK</string>
-   </property>
-   <property name="autoDefault">
-    <bool>false</bool>
-   </property>
-  </widget>
- </widget>
- <resources/>
- <connections/>
-</ui>