separate controller backend frontend

Change-Id: Ic4ba9c8154a600c978e75ea82ff36569270dd656
diff --git a/src/chat-dialog-backend.cpp b/src/chat-dialog-backend.cpp
index 87eed37..680d24b 100644
--- a/src/chat-dialog-backend.cpp
+++ b/src/chat-dialog-backend.cpp
@@ -61,8 +61,6 @@
 void
 ChatDialogBackend::initializeSync()
 {
-  QMutexLocker locker(&mutex);
-
   // if a SyncSocket is running, turn it off
   if (static_cast<bool>(m_sock)) {
     if (m_joined)
@@ -375,6 +373,14 @@
 void
 ChatDialogBackend::shutdown()
 {
+  if (static_cast<bool>(m_sock)) {
+    if (m_joined)
+      sendLeave();
+    m_sock.reset();
+
+    usleep(100000);
+  }
+
   m_face.getIoService().stop();
 }
 
diff --git a/src/chat-dialog-backend.hpp b/src/chat-dialog-backend.hpp
index eda4094..09c52a6 100644
--- a/src/chat-dialog-backend.hpp
+++ b/src/chat-dialog-backend.hpp
@@ -144,8 +144,6 @@
   ndn::Scheduler m_scheduler;            // scheduler
   ndn::EventId m_helloEventId;           // event id of timeout
 
-  QMutex mutex;                          // mutex used for prefix updates
-
   bool m_joined;                         // true if in a chatroom
 
   BackendRoster m_roster;                // User roster
diff --git a/src/contact-manager.cpp b/src/contact-manager.cpp
index 742b7c3..69c2d4b 100644
--- a/src/contact-manager.cpp
+++ b/src/contact-manager.cpp
@@ -50,7 +50,7 @@
 using ndn::OnInterestValidationFailed;
 
 
-ContactManager::ContactManager(shared_ptr<Face> face,
+ContactManager::ContactManager(Face& face,
                                QObject* parent)
   : QObject(parent)
   , m_face(face)
@@ -109,7 +109,7 @@
 {
   shared_ptr<IdentityCertificate> anchor = loadTrustAnchor();
 
-  shared_ptr<ValidatorRegex> validator = make_shared<ValidatorRegex>(boost::ref(*m_face));
+  shared_ptr<ValidatorRegex> validator = make_shared<ValidatorRegex>(boost::ref(m_face));
   validator->addDataVerificationRule(make_shared<SecRuleRelative>("^([^<DNS>]*)<DNS><ENDORSED>",
                                                                   "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$",
                                                                   "==", "\\1", "\\1\\2", true));
@@ -170,12 +170,12 @@
   interest.setInterestLifetime(time::milliseconds(1000));
   interest.setMustBeFresh(true);
 
-  m_face->expressInterest(interest,
-                          bind(&ContactManager::onEndorseCertificateInternal,
-                               this, _1, _2, identity, certIndex,
-                               endorseCollection->endorsement(certIndex).hash()),
-                          bind(&ContactManager::onEndorseCertificateInternalTimeout,
-                               this, _1, identity, certIndex));
+  m_face.expressInterest(interest,
+                         bind(&ContactManager::onEndorseCertificateInternal,
+                              this, _1, _2, identity, certIndex,
+                              endorseCollection->endorsement(certIndex).hash()),
+                         bind(&ContactManager::onEndorseCertificateInternalTimeout,
+                              this, _1, identity, certIndex));
 }
 
 void
@@ -420,7 +420,7 @@
   m_keyChain.signByIdentity(*data, m_identity);
 
   m_contactStorage->updateDnsOthersEndorse(*data);
-  m_face->put(*data);
+  m_face.put(*data);
 }
 
 void
@@ -507,7 +507,7 @@
   m_keyChain.signByIdentity(*data, m_identity);
 
   m_contactStorage->updateDnsSelfProfileData(*data);
-  m_face->put(*data);
+  m_face.put(*data);
 }
 
 shared_ptr<EndorseCertificate>
@@ -552,7 +552,7 @@
   m_keyChain.signByIdentity(*data, m_identity);
 
   m_contactStorage->updateDnsEndorseOthers(*data, dnsName.get(-3).toUri());
-  m_face->put(*data);
+  m_face.put(*data);
 }
 
 void
@@ -562,11 +562,11 @@
                              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));
+  m_face.expressInterest(interest,
+                         bind(&ContactManager::onTargetData,
+                              this, _1, _2, onValidated, onValidationFailed),
+                         bind(&ContactManager::onTargetTimeout,
+                              this, _1, retry, onValidated, onValidationFailed, timeoutNotify));
 }
 
 void
@@ -605,7 +605,7 @@
   if (interestName.size() == (prefix.size()+1)) {
     data = m_contactStorage->getDnsData("N/A", interestName.get(prefix.size()).toUri());
     if (static_cast<bool>(data))
-      m_face->put(*data);
+      m_face.put(*data);
     return;
   }
 
@@ -613,7 +613,7 @@
     data = m_contactStorage->getDnsData(interestName.get(prefix.size()).toUri(),
                                         interestName.get(prefix.size()+1).toUri());
     if (static_cast<bool>(data))
-      m_face->put(*data);
+      m_face.put(*data);
     return;
   }
 }
@@ -633,16 +633,19 @@
 
   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));
+  const ndn::RegisteredPrefixId* dnsListenerId =
+    m_face.setInterestFilter(dnsPrefix,
+                             bind(&ContactManager::onDnsInterest,
+                                  this, _1, _2),
+                             bind(&ContactManager::onDnsRegisterFailed,
+                                  this, _1, _2));
+
+  if (m_dnsListenerId != 0)
+    m_face.unsetInterestFilter(m_dnsListenerId);
+
+  m_dnsListenerId = dnsListenerId;
 
   m_contactList.clear();
   m_contactStorage->getAllContacts(m_contactList);
diff --git a/src/contact-manager.hpp b/src/contact-manager.hpp
index d9254d9..6c43bac 100644
--- a/src/contact-manager.hpp
+++ b/src/contact-manager.hpp
@@ -36,7 +36,7 @@
   Q_OBJECT
 
 public:
-  ContactManager(shared_ptr<ndn::Face> m_face, QObject* parent = 0);
+  ContactManager(ndn::Face& m_face, QObject* parent = 0);
 
   ~ContactManager();
 
@@ -269,7 +269,7 @@
   // Conf
   shared_ptr<ContactStorage> m_contactStorage;
   shared_ptr<ndn::Validator> m_validator;
-  shared_ptr<ndn::Face> m_face;
+  ndn::Face& m_face;
   ndn::KeyChain m_keyChain;
   Name m_identity;
   ContactList m_contactList;
diff --git a/src/controller-backend.cpp b/src/controller-backend.cpp
new file mode 100644
index 0000000..af84cd7
--- /dev/null
+++ b/src/controller-backend.cpp
@@ -0,0 +1,360 @@
+/* -*- 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 "controller-backend.hpp"
+
+#ifndef Q_MOC_RUN
+#include "invitation.hpp"
+#include "logging.h"
+#endif
+
+
+INIT_LOGGER("ControllerBackend");
+
+namespace chronos {
+
+using std::string;
+
+using ndn::Face;
+using ndn::IdentityCertificate;
+using ndn::OnInterestValidated;
+using ndn::OnInterestValidationFailed;
+
+
+static const uint8_t ROUTING_PREFIX_SEPARATOR[2] = {0xF0, 0x2E};
+
+ControllerBackend::ControllerBackend(QObject* parent)
+  : QThread(parent)
+  , m_contactManager(m_face)
+  , m_invitationListenerId(0)
+{
+  // connection to contact manager
+  connect(this, SIGNAL(identityUpdated(const QString&)),
+          &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
+
+  connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
+          this, SLOT(onContactIdListReady(const QStringList&)));
+
+}
+
+ControllerBackend::~ControllerBackend()
+{
+}
+
+void
+ControllerBackend::run()
+{
+  setInvitationListener();
+
+  m_face.processEvents();
+
+  std::cerr << "Bye!" << std::endl;
+}
+
+// private methods:
+
+void
+tmpOnInvitationInterest(const ndn::Name& prefix,
+                        const ndn::Interest& interest)
+{
+  std::cerr << "tmpOnInvitationInterest" << std::endl;
+}
+
+void
+tmpOnInvitationRegisterFailed(const Name& prefix,
+                              const string& failInfo)
+{
+  std::cerr << "tmpOnInvitationRegisterFailed" << std::endl;
+}
+
+void
+tmpUnregisterPrefixSuccessCallback()
+{
+  std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
+}
+
+void
+tmpUnregisterPrefixFailureCallback(const string& failInfo)
+{
+  std::cerr << "tmpUnregisterPrefixSuccessCallback" << std::endl;
+}
+
+void
+ControllerBackend::setInvitationListener()
+{
+  QMutexLocker locker(&m_mutex);
+
+  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");
+
+  const ndn::RegisteredPrefixId* invitationListenerId =
+    m_face.setInterestFilter(invitationPrefix,
+                             bind(&ControllerBackend::onInvitationInterest,
+                                  this, _1, _2, offset),
+                             bind(&ControllerBackend::onInvitationRegisterFailed,
+                                  this, _1, _2));
+
+  if (m_invitationListenerId != 0) {
+    m_face.unregisterPrefix(m_invitationListenerId,
+                            bind(&ControllerBackend::onInvitationPrefixReset, this),
+                            bind(&ControllerBackend::onInvitationPrefixResetFailed, this, _1));
+  }
+
+  m_invitationListenerId = invitationListenerId;
+
+}
+
+ndn::Name
+ControllerBackend::getInvitationRoutingPrefix()
+{
+  return Name("/ndn/broadcast");
+}
+
+void
+ControllerBackend::onInvitationPrefixReset()
+{
+  // _LOG_DEBUG("ControllerBackend::onInvitationPrefixReset");
+}
+
+void
+ControllerBackend::onInvitationPrefixResetFailed(const std::string& failInfo)
+{
+  // _LOG_DEBUG("ControllerBackend::onInvitationPrefixResetFailed: " << failInfo);
+}
+
+
+void
+ControllerBackend::onInvitationInterest(const ndn::Name& prefix,
+                                        const ndn::Interest& interest,
+                                        size_t routingPrefixOffset)
+{
+  // _LOG_DEBUG("onInvitationInterest: " << interest.getName());
+  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.contains(QString::fromStdString(invitation.getChatroom())))
+        return;
+  }
+  catch (Invitation::Error& e) {
+    // Cannot parse the invitation;
+    return;
+  }
+
+  OnInterestValidated onValidated = bind(&ControllerBackend::onInvitationValidated, this, _1);
+  OnInterestValidationFailed onFailed = bind(&ControllerBackend::onInvitationValidationFailed,
+                                             this, _1, _2);
+
+  m_validator.validate(*invitationInterest, onValidated, onFailed);
+}
+
+void
+ControllerBackend::onInvitationRegisterFailed(const Name& prefix, const string& failInfo)
+{
+  // _LOG_DEBUG("ControllerBackend::onInvitationRegisterFailed: " << failInfo);
+}
+
+void
+ControllerBackend::onInvitationValidated(const shared_ptr<const Interest>& interest)
+{
+  Invitation invitation(interest->getName());
+  // Should be obtained via a method of ContactManager.
+  string alias = invitation.getInviterCertificate().getPublicKeyName().getPrefix(-1).toUri();
+
+  emit invitaionValidated(QString::fromStdString(alias),
+                          QString::fromStdString(invitation.getChatroom()),
+                          interest->getName());
+}
+
+void
+ControllerBackend::onInvitationValidationFailed(const shared_ptr<const Interest>& interest,
+                                                string failureInfo)
+{
+  // _LOG_DEBUG("Invitation: " << interest->getName() <<
+  //            " cannot not be validated due to: " << failureInfo);
+}
+
+void
+ControllerBackend::onLocalPrefix(const Interest& interest, Data& data)
+{
+  Name prefix;
+
+  Block contentBlock = data.getContent();
+  try {
+    contentBlock.parse();
+
+    for (Block::element_const_iterator it = contentBlock.elements_begin();
+         it != contentBlock.elements_end(); it++) {
+      Name candidate;
+      candidate.wireDecode(*it);
+      if (candidate.isPrefixOf(m_identity)) {
+        prefix = candidate;
+        break;
+      }
+    }
+
+    if (prefix.empty()) {
+      if (contentBlock.elements_begin() != contentBlock.elements_end())
+        prefix.wireDecode(*contentBlock.elements_begin());
+      else
+        prefix = Name("/private/local");
+    }
+  }
+  catch (Block::Error& e) {
+    prefix = Name("/private/local");
+  }
+
+  updateLocalPrefix(prefix);
+}
+
+void
+ControllerBackend::onLocalPrefixTimeout(const Interest& interest)
+{
+  Name localPrefix("/private/local");
+  updateLocalPrefix(localPrefix);
+}
+
+void
+ControllerBackend::updateLocalPrefix(const Name& localPrefix)
+{
+  if (m_localPrefix.empty() || m_localPrefix != localPrefix) {
+    m_localPrefix = localPrefix;
+    emit localPrefixUpdated(QString::fromStdString(localPrefix.toUri()));
+  }
+}
+
+// public slots:
+void
+ControllerBackend::shutdown()
+{
+  m_face.getIoService().stop();
+}
+
+void
+ControllerBackend::addChatroom(QString chatroom)
+{
+  m_chatDialogList.append(chatroom);
+}
+
+void
+ControllerBackend::removeChatroom(QString chatroom)
+{
+  m_chatDialogList.removeAll(chatroom);
+}
+
+void
+ControllerBackend::onUpdateLocalPrefixAction()
+{
+  // Name interestName();
+  Interest interest("/localhop/ndn-autoconf/routable-prefixes");
+  interest.setInterestLifetime(time::milliseconds(1000));
+  interest.setMustBeFresh(true);
+
+  m_face.expressInterest(interest,
+                         bind(&ControllerBackend::onLocalPrefix, this, _1, _2),
+                         bind(&ControllerBackend::onLocalPrefixTimeout, this, _1));
+}
+
+void
+ControllerBackend::onIdentityChanged(const QString& identity)
+{
+  m_chatDialogList.clear();
+
+  m_identity = Name(identity.toStdString());
+
+  std::cerr << "ControllerBackend::onIdentityChanged: " << m_identity << std::endl;
+
+  m_keyChain.createIdentity(m_identity);
+
+  setInvitationListener();
+
+  emit identityUpdated(identity);
+}
+
+void
+ControllerBackend::onInvitationResponded(const ndn::Name& invitationName, bool accepted)
+{
+  shared_ptr<Data> response = make_shared<Data>();
+  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(time::milliseconds(1000));
+  }
+  else {
+    response->setName(invitationName);
+    response->setFreshnessPeriod(time::milliseconds(1000));
+  }
+
+  m_keyChain.signByIdentity(*response, m_identity);
+
+  // Check if we need a wrapper
+  Name invitationRoutingPrefix = getInvitationRoutingPrefix();
+  if (invitationRoutingPrefix.isPrefixOf(m_identity))
+    m_face.put(*response);
+  else {
+    Name wrappedName;
+    wrappedName.append(invitationRoutingPrefix)
+      .append(ROUTING_PREFIX_SEPARATOR, 2)
+      .append(response->getName());
+
+    // _LOG_DEBUG("onInvitationResponded: prepare reply " << wrappedName);
+
+    shared_ptr<Data> wrappedData = make_shared<Data>(wrappedName);
+    wrappedData->setContent(response->wireEncode());
+    wrappedData->setFreshnessPeriod(time::milliseconds(1000));
+
+    m_keyChain.signByIdentity(*wrappedData, m_identity);
+    m_face.put(*wrappedData);
+  }
+
+  Invitation invitation(invitationName);
+  emit startChatroomOnInvitation(invitation, true);
+}
+
+void
+ControllerBackend::onContactIdListReady(const QStringList& list)
+{
+  ContactList contactList;
+
+  m_contactManager.getContactList(contactList);
+  m_validator.cleanTrustAnchor();
+
+  for (ContactList::const_iterator it  = contactList.begin(); it != contactList.end(); it++)
+    m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
+
+}
+
+
+} // namespace chronos
+
+#if WAF
+#include "controller-backend.moc"
+// #include "controller-backend.cpp.moc"
+#endif
diff --git a/src/controller-backend.hpp b/src/controller-backend.hpp
new file mode 100644
index 0000000..2456641
--- /dev/null
+++ b/src/controller-backend.hpp
@@ -0,0 +1,143 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHRONOCHAT_CONTROLLER_BACKEND_HPP
+#define CHRONOCHAT_CONTROLLER_BACKEND_HPP
+
+#include <QThread>
+#include <QStringList>
+#include <QMutex>
+
+#ifndef Q_MOC_RUN
+#include "common.hpp"
+#include "contact-manager.hpp"
+#include "invitation.hpp"
+#include "validator-invitation.hpp"
+#include <ndn-cxx/security/key-chain.hpp>
+#endif
+
+namespace chronos {
+
+class ControllerBackend : public QThread
+{
+  Q_OBJECT
+
+public:
+  ControllerBackend(QObject* parent = 0);
+
+  ~ControllerBackend();
+
+  ContactManager*
+  getContactManager()
+  {
+    return &m_contactManager;
+  }
+
+protected:
+  void
+  run();
+
+private:
+  void
+  setInvitationListener();
+
+  ndn::Name
+  getInvitationRoutingPrefix();
+
+  void
+  onInvitationPrefixReset();
+
+  void
+  onInvitationPrefixResetFailed(const std::string& failInfo);
+
+  void
+  onInvitationInterest(const ndn::Name& prefix, const ndn::Interest& interest,
+                       size_t routingPrefixOffset);
+
+  void
+  onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo);
+
+  void
+  onInvitationValidated(const shared_ptr<const Interest>& interest);
+
+  void
+  onInvitationValidationFailed(const shared_ptr<const Interest>& interest,
+                               std::string failureInfo);
+
+  void
+  onLocalPrefix(const Interest& interest, Data& data);
+
+  void
+  onLocalPrefixTimeout(const Interest& interest);
+
+  void
+  updateLocalPrefix(const Name& localPrefix);
+
+signals:
+  void
+  identityUpdated(const QString& identity);
+
+  void
+  localPrefixUpdated(const QString& localPrefix);
+
+  void
+  invitaionValidated(QString alias, QString chatroom, ndn::Name invitationINterest);
+
+  void
+  startChatroomOnInvitation(chronos::Invitation invitation, bool secured);
+
+public slots:
+  void
+  shutdown();
+
+  void
+  addChatroom(QString chatroom);
+
+  void
+  removeChatroom(QString chatroom);
+
+  void
+  onUpdateLocalPrefixAction();
+
+  void
+  onIdentityChanged(const QString& identity);
+
+  void
+  onInvitationResponded(const ndn::Name& invitationName, bool accepted);
+
+private slots:
+  void
+  onContactIdListReady(const QStringList& list);
+
+private:
+  ndn::Face m_face;
+
+  Name m_identity;  //TODO: set/get
+
+  Name m_localPrefix;
+
+  // Contact Manager
+  ContactManager m_contactManager;
+
+  // Security related;
+  ndn::KeyChain m_keyChain;
+  ValidatorInvitation m_validator;
+
+  // RegisteredPrefixId
+  const ndn::RegisteredPrefixId* m_invitationListenerId;
+
+  // ChatRoomList
+  QStringList m_chatDialogList;
+
+  QMutex m_mutex;
+};
+
+} // namespace chronos
+
+#endif // CHRONOCHAT_CONTROLLER_BACKEND_HPP
diff --git a/src/controller.cpp b/src/controller.cpp
index b52c188..12e31b8 100644
--- a/src/controller.cpp
+++ b/src/controller.cpp
@@ -19,14 +19,13 @@
 #include <boost/filesystem.hpp>
 #include <boost/lexical_cast.hpp>
 #include <ndn-cxx/util/random.hpp>
-#include "invitation.hpp"
 #include "cryptopp.hpp"
 #include "config.pb.h"
 #include "endorse-info.pb.h"
 #include "logging.h"
 #endif
 
-// INIT_LOGGER("chronos.Controller");
+INIT_LOGGER("chronos.Controller");
 
 Q_DECLARE_METATYPE(ndn::Name)
 Q_DECLARE_METATYPE(ndn::IdentityCertificate)
@@ -34,28 +33,16 @@
 Q_DECLARE_METATYPE(ndn::Interest)
 Q_DECLARE_METATYPE(size_t)
 Q_DECLARE_METATYPE(chronos::ChatroomInfo)
+Q_DECLARE_METATYPE(chronos::Invitation)
 
 namespace chronos {
 
 using std::string;
 
-using ndn::Face;
-using ndn::IdentityCertificate;
-using ndn::OnInterestValidated;
-using ndn::OnInterestValidationFailed;
-
-static const uint8_t ROUTING_PREFIX_SEPARATOR[2] = {0xF0, 0x2E};
-
 // constructor & destructor
-Controller::Controller(shared_ptr<Face> face,
-                       QWidget* parent)
+Controller::Controller(QWidget* parent)
   : QDialog(parent)
-  , m_face(face)
   , m_localPrefixDetected(false)
-  , m_invitationListenerId(0)
-  , m_contactManager(m_face)
-  , m_discoveryLogic(m_face,
-                     bind(&Controller::updateDiscoveryList, this, _1, _2))
   , m_settingDialog(new SettingDialog)
   , m_startChatDialog(new StartChatDialog)
   , m_profileEditor(new ProfileEditor)
@@ -63,7 +50,6 @@
   , m_contactPanel(new ContactPanel)
   , m_browseContactDialog(new BrowseContactDialog)
   , m_addContactPanel(new AddContactPanel)
-  , m_chatroomDiscoveryDialog(new ChatroomDiscoveryDialog)
 {
   qRegisterMetaType<ndn::Name>("ndn.Name");
   qRegisterMetaType<ndn::IdentityCertificate>("ndn.IdentityCertificate");
@@ -71,23 +57,15 @@
   qRegisterMetaType<ndn::Interest>("ndn.Interest");
   qRegisterMetaType<size_t>("size_t");
   qRegisterMetaType<chronos::ChatroomInfo>("chronos.Chatroom");
-
-  connect(this, SIGNAL(localPrefixUpdated(const QString&)),
-          this, SLOT(onLocalPrefixUpdated(const QString&)));
-  connect(this, SIGNAL(invitationInterest(const ndn::Name&, const ndn::Interest&, size_t)),
-          this, SLOT(onInvitationInterest(const ndn::Name&, const ndn::Interest&, size_t)));
+  qRegisterMetaType<chronos::Invitation>("chronos.Invitation");
 
   // Connection to ContactManager
-  connect(this, SIGNAL(identityUpdated(const QString&)),
-          &m_contactManager, SLOT(onIdentityUpdated(const QString&)));
-  connect(&m_contactManager, SIGNAL(warning(const QString&)),
+  connect(m_backend.getContactManager(), SIGNAL(warning(const QString&)),
           this, SLOT(onWarning(const QString&)));
   connect(this, SIGNAL(refreshBrowseContact()),
-          &m_contactManager, SLOT(onRefreshBrowseContact()));
-  connect(&m_contactManager, SIGNAL(contactInfoFetchFailed(const QString&)),
+          m_backend.getContactManager(), SLOT(onRefreshBrowseContact()));
+  connect(m_backend.getContactManager(), 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&)),
@@ -96,8 +74,6 @@
           this, SLOT(onIdentityUpdated(const QString&)));
   connect(m_settingDialog, SIGNAL(nickUpdated(const QString&)),
           this, SLOT(onNickUpdated(const QString&)));
-  connect(this, SIGNAL(localPrefixUpdated(const QString&)),
-          m_settingDialog, SLOT(onLocalPrefixUpdated(const QString&)));
   connect(m_settingDialog, SIGNAL(prefixUpdated(const QString&)),
           this, SLOT(onLocalPrefixConfigured(const QString&)));
 
@@ -107,7 +83,7 @@
   connect(this, SIGNAL(identityUpdated(const QString&)),
           m_profileEditor, SLOT(onIdentityUpdated(const QString&)));
   connect(m_profileEditor, SIGNAL(updateProfile()),
-          &m_contactManager, SLOT(onUpdateProfile()));
+          m_backend.getContactManager(), SLOT(onUpdateProfile()));
 
   // Connection to StartChatDialog
   connect(m_startChatDialog, SIGNAL(startChatroom(const QString&, bool)),
@@ -115,72 +91,95 @@
 
   // Connection to InvitationDialog
   connect(m_invitationDialog, SIGNAL(invitationResponded(const ndn::Name&, bool)),
-          this, SLOT(onInvitationResponded(const ndn::Name&, bool)));
+          &m_backend, SLOT(onInvitationResponded(const ndn::Name&, bool)));
 
   // Connection to AddContactPanel
   connect(m_addContactPanel, SIGNAL(fetchInfo(const QString&)),
-          &m_contactManager, SLOT(onFetchContactInfo(const QString&)));
+          m_backend.getContactManager(), 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&)));
+          m_backend.getContactManager(), SLOT(onAddFetchedContact(const QString&)));
+  connect(m_backend.getContactManager(),
+          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&)));
+          m_backend.getContactManager(), 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_backend.getContactManager(), SLOT(onAddFetchedContactIdCert(const QString&)));
+  connect(m_backend.getContactManager(), SIGNAL(idCertNameListReady(const QStringList&)),
           m_browseContactDialog, SLOT(onIdCertNameListReady(const QStringList&)));
-  connect(&m_contactManager, SIGNAL(nameListReady(const QStringList&)),
+  connect(m_backend.getContactManager(), SIGNAL(nameListReady(const QStringList&)),
           m_browseContactDialog, SLOT(onNameListReady(const QStringList&)));
-  connect(&m_contactManager, SIGNAL(idCertReady(const ndn::IdentityCertificate&)),
+  connect(m_backend.getContactManager(), SIGNAL(idCertReady(const ndn::IdentityCertificate&)),
           m_browseContactDialog, SLOT(onIdCertReady(const ndn::IdentityCertificate&)));
 
   // Connection to ContactPanel
   connect(m_contactPanel, SIGNAL(waitForContactList()),
-          &m_contactManager, SLOT(onWaitForContactList()));
+          m_backend.getContactManager(), SLOT(onWaitForContactList()));
   connect(m_contactPanel, SIGNAL(waitForContactInfo(const QString&)),
-          &m_contactManager, SLOT(onWaitForContactInfo(const QString&)));
+          m_backend.getContactManager(), SLOT(onWaitForContactInfo(const QString&)));
   connect(m_contactPanel, SIGNAL(removeContact(const QString&)),
-          &m_contactManager, SLOT(onRemoveContact(const QString&)));
+          m_backend.getContactManager(), SLOT(onRemoveContact(const QString&)));
   connect(m_contactPanel, SIGNAL(updateAlias(const QString&, const QString&)),
-          &m_contactManager, SLOT(onUpdateAlias(const QString&, const QString&)));
+          m_backend.getContactManager(), SLOT(onUpdateAlias(const QString&, const QString&)));
   connect(m_contactPanel, SIGNAL(updateIsIntroducer(const QString&, bool)),
-          &m_contactManager, SLOT(onUpdateIsIntroducer(const QString&, bool)));
+          m_backend.getContactManager(), SLOT(onUpdateIsIntroducer(const QString&, bool)));
   connect(m_contactPanel, SIGNAL(updateEndorseCertificate(const QString&)),
-          &m_contactManager, SLOT(onUpdateEndorseCertificate(const QString&)));
+          m_backend.getContactManager(), 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&)),
+  connect(m_backend.getContactManager(), SIGNAL(contactAliasListReady(const QStringList&)),
           m_contactPanel, SLOT(onContactAliasListReady(const QStringList&)));
-  connect(&m_contactManager, SIGNAL(contactIdListReady(const QStringList&)),
+  connect(m_backend.getContactManager(), SIGNAL(contactIdListReady(const QStringList&)),
           m_contactPanel, SLOT(onContactIdListReady(const QStringList&)));
-  connect(&m_contactManager, SIGNAL(contactInfoReady(const QString&, const QString&,
-                                                     const QString&, bool)),
+  connect(m_backend.getContactManager(), SIGNAL(contactInfoReady(const QString&, const QString&,
+                                                                 const QString&, bool)),
           m_contactPanel, SLOT(onContactInfoReady(const QString&, const QString&,
                                                   const QString&, bool)));
 
-  // Connection to DiscoveryDialog
-  connect(this,
-          SIGNAL(discoverChatroomChanged(const chronos::ChatroomInfo&, bool)),
-          m_chatroomDiscoveryDialog,
-          SLOT(onDiscoverChatroomChanged(const chronos::ChatroomInfo&, bool)));
-  connect(m_chatroomDiscoveryDialog, SIGNAL(startChatroom(const QString&, bool)),
-          this, SLOT(onStartChatroom(const QString&, bool)));
+  // Connection to backend thread
+  connect(this, SIGNAL(shutdownBackend()),
+          &m_backend, SLOT(shutdown()));
+  connect(this, SIGNAL(updateLocalPrefix()),
+          &m_backend, SLOT(onUpdateLocalPrefixAction()));
+  connect(this, SIGNAL(identityUpdated(const QString&)),
+          &m_backend, SLOT(onIdentityChanged(const QString&)));
+  connect(this, SIGNAL(addChatroom(QString)),
+          &m_backend, SLOT(addChatroom(QString)));
+  connect(this, SIGNAL(removeChatroom(QString)),
+          &m_backend, SLOT(removeChatroom(QString)));
+
+  // Thread notifications:
+  // on local prefix udpated:
+  connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
+          this, SLOT(onLocalPrefixUpdated(const QString&)));
+  connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
+          m_settingDialog, SLOT(onLocalPrefixUpdated(const QString&)));
+
+  // on invitation validated:
+  connect(&m_backend, SIGNAL(invitaionValidated(QString, QString, ndn::Name)),
+          m_invitationDialog, SLOT(onInvitationReceived(QString, QString, ndn::Name)));
+
+  // on invitation accepted:
+  connect(&m_backend, SIGNAL(startChatroomOnInvitation(chronos::Invitation, bool)),
+          this, SLOT(onStartChatroom2(chronos::Invitation, bool)));
+
+  m_backend.start();
 
   initialize();
 
   createTrayIcon();
 
-  onUpdateLocalPrefixAction();
+  emit updateLocalPrefix();
 }
 
 Controller::~Controller()
@@ -232,37 +231,9 @@
 {
   loadConf();
 
-  m_keyChain.createIdentity(m_identity);
-
   openDB();
 
   emit identityUpdated(QString(m_identity.toUri().c_str()));
-
-  setInvitationListener();
-
-  m_discoveryLogic.sendDiscoveryInterest();
-}
-
-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::onInvitationInterestWrapper,
-                                                          this, _1, _2, offset),
-                                                     bind(&Controller::onInvitationRegisterFailed,
-                                                          this, _1, _2));
 }
 
 void
@@ -333,7 +304,8 @@
   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()));
+  connect(m_updateLocalPrefixAction, SIGNAL(triggered()),
+          &m_backend, SLOT(onUpdateLocalPrefixAction()));
 
   m_minimizeAction = new QAction(tr("Mi&nimize"), this);
   connect(m_minimizeAction, SIGNAL(triggered()), this, SLOT(onMinimizeAction()));
@@ -350,7 +322,7 @@
 
   m_trayIconMenu = new QMenu(this);
   m_trayIconMenu->addAction(m_startChatroom);
-  m_trayIconMenu->addAction(m_discoveryAction);
+  // m_trayIconMenu->addAction(m_discoveryAction); // disable discovery temporarily
 
   m_trayIconMenu->addSeparator();
   m_trayIconMenu->addAction(m_settingsAction);
@@ -382,7 +354,7 @@
   QMenu* closeMenu = 0;
 
   menu->addAction(m_startChatroom);
-  menu->addAction(m_discoveryAction);
+  // menu->addAction(m_discoveryAction);
 
   menu->addSeparator();
   menu->addAction(m_settingsAction);
@@ -422,88 +394,6 @@
   m_closeMenu = closeMenu;
 }
 
-void
-Controller::onLocalPrefix(const Interest& interest, Data& data)
-{
-  QString localPrefixStr("/private/local");
-  Name prefix;
-
-  Block contentBlock = data.getContent();
-  try {
-    contentBlock.parse();
-
-    for (Block::element_const_iterator it = contentBlock.elements_begin();
-         it != contentBlock.elements_end(); it++) {
-      Name candidate;
-      candidate.wireDecode(*it);
-      if (candidate.isPrefixOf(m_identity)) {
-        prefix = candidate;
-        break;
-      }
-    }
-
-    if (prefix.empty()) {
-      if (contentBlock.elements_begin() != contentBlock.elements_end())
-        prefix.wireDecode(*contentBlock.elements_begin());
-      else
-        prefix = Name("/private/local");
-    }
-
-    localPrefixStr = QString::fromStdString(prefix.toUri());
-  }
-  catch (Block::Error& e) {
-    prefix = Name("/private/local");
-  }
-
-  if (m_localPrefix.empty() || m_localPrefix != prefix) {
-    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::onInvitationInterestWrapper(const Name& prefix,
-                                        const Interest& interest,
-                                        size_t routingPrefixOffset)
-{
-  emit invitationInterest(prefix, interest, routingPrefixOffset);
-}
-
-void
-Controller::onInvitationRegisterFailed(const Name& prefix, const string& failInfo)
-{
-  // _LOG_DEBUG("Controller::onInvitationRegisterFailed: " << failInfo);
-}
-
-void
-Controller::onInvitationValidated(const shared_ptr<const Interest>& interest)
-{
-  Invitation invitation(interest->getName());
-  // Should be obtained via a method of ContactManager.
-  string alias = invitation.getInviterCertificate().getPublicKeyName().getPrefix(-1).toUri();
-
-  m_invitationDialog->setInvitation(alias, invitation.getChatroom(), interest->getName());
-  m_invitationDialog->show();
-}
-
-void
-Controller::onInvitationValidationFailed(const shared_ptr<const Interest>& interest,
-                                         string failureInfo)
-{
-  // _LOG_DEBUG("Invitation: " << interest->getName() <<
-  //            " cannot not be validated due to: " << failureInfo);
-}
-
 string
 Controller::getRandomString()
 {
@@ -528,17 +418,10 @@
   return ss.str();
 }
 
-ndn::Name
-Controller::getInvitationRoutingPrefix()
-{
-  return Name("/ndn/broadcast");
-}
-
 void
 Controller::addChatDialog(const QString& chatroomName, ChatDialog* chatDialog)
 {
   m_chatDialogList[chatroomName.toStdString()] = chatDialog;
-  m_discoveryLogic.addLocalChatroom(*chatDialog->getChatroomInfo());
   connect(chatDialog, SIGNAL(closeChatDialog(const QString&)),
           this, SLOT(onRemoveChatDialog(const QString&)));
   connect(chatDialog, SIGNAL(showChatMessage(const QString&, const QString&, const QString&)),
@@ -547,7 +430,7 @@
           this, SLOT(onResetIcon()));
   connect(chatDialog, SIGNAL(rosterChanged(const chronos::ChatroomInfo&)),
           this, SLOT(onRosterChanged(const chronos::ChatroomInfo&)));
-  connect(this, SIGNAL(localPrefixUpdated(const QString&)),
+  connect(&m_backend, SIGNAL(localPrefixUpdated(const QString&)),
           chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
   connect(this, SIGNAL(localPrefixConfigured(const QString&)),
           chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
@@ -574,21 +457,17 @@
 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);
-  setInvitationListener();
-
   emit closeDBModule();
 
-  QTimer::singleShot(500, this, SLOT(onIdentityUpdatedContinued()));
+  Name identityName(identity.toStdString());
+  m_identity = identityName;
 
+  QTimer::singleShot(500, this, SLOT(onIdentityUpdatedContinued()));
 }
 
 void
@@ -605,19 +484,6 @@
 }
 
 void
-Controller::onContactIdListReady(const QStringList& list)
-{
-  ContactList contactList;
-
-  m_contactManager.getContactList(contactList);
-  m_validator.cleanTrustAnchor();
-
-  for (ContactList::const_iterator it  = contactList.begin(); it != contactList.end(); it++)
-    m_validator.addTrustAnchor((*it)->getPublicKeyName(), (*it)->getPublicKey());
-
-}
-
-void
 Controller::onNickUpdated(const QString& nick)
 {
   m_nick = nick.toStdString();
@@ -628,12 +494,12 @@
 {
   QString privateLocalPrefix("/private/local");
 
-  m_localPrefix = Name(localPrefix.toStdString());
-
   if (privateLocalPrefix != localPrefix)
     m_localPrefixDetected = true;
   else
     m_localPrefixDetected = false;
+
+  m_localPrefix = Name(localPrefix.toStdString());
 }
 
 void
@@ -658,11 +524,6 @@
 void
 Controller::onDiscoveryAction()
 {
-  m_discoveryLogic.sendDiscoveryInterest();
-
-  m_chatroomDiscoveryDialog->updateChatroomList();
-  m_chatroomDiscoveryDialog->show();
-  m_chatroomDiscoveryDialog->raise();
 }
 
 
@@ -704,19 +565,6 @@
 }
 
 void
-Controller::onUpdateLocalPrefixAction()
-{
-  // Name interestName();
-  Interest interest("/localhop/ndn-autoconf/routable-prefixes");
-  interest.setInterestLifetime(time::milliseconds(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();
@@ -739,9 +587,6 @@
     it->second->shutdown();
   }
 
-  if (m_invitationListenerId != 0)
-    m_face->unsetInterestFilter(m_invitationListenerId);
-
   delete m_settingDialog;
   delete m_startChatDialog;
   delete m_profileEditor;
@@ -749,7 +594,10 @@
   delete m_browseContactDialog;
   delete m_addContactPanel;
 
-  m_face->getIoService().stop();
+  if (m_backend.isRunning()) {
+    emit shutdownBackend();
+    m_backend.wait();
+  }
 
   QApplication::quit();
 }
@@ -774,10 +622,6 @@
   // 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.
-  // std::cout << "start chat room localprefix: " << m_localPrefix.toUri() << std::endl;
-  shared_ptr<IdentityCertificate> idCert
-    = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(m_identity));
-
   Name chatPrefix;
   chatPrefix.append(m_identity).append("CHRONOCHAT-DATA").append(chatroomName.toStdString());
 
@@ -790,89 +634,23 @@
 
   addChatDialog(chatroomName, chatDialog);
   chatDialog->show();
+
+  emit addChatroom(chatroomName);
 }
 
 void
-Controller::onInvitationResponded(const ndn::Name& invitationName, bool accepted)
+Controller::onStartChatroom2(chronos::Invitation invitation, bool secured)
 {
-  shared_ptr<Data> response = make_shared<Data>();
-  shared_ptr<IdentityCertificate> chatroomCert;
+  QString chatroomName = QString::fromStdString(invitation.getChatroom());
+  onStartChatroom(chatroomName, secured);
 
-  // generate reply;
-  if (accepted) {
-    Name responseName = invitationName;
-    responseName.append(m_localPrefix.wireEncode());
+  ChatDialogList::iterator it = m_chatDialogList.find(chatroomName.toStdString());
 
-    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(time::milliseconds(1000));
-  }
-  else {
-    response->setName(invitationName);
-    response->setFreshnessPeriod(time::milliseconds(1000));
-  }
-
-  m_keyChain.signByIdentity(*response, m_identity);
-
-  // Check if we need a wrapper
-  Name invitationRoutingPrefix = getInvitationRoutingPrefix();
-  if (invitationRoutingPrefix.isPrefixOf(m_identity))
-    m_face->put(*response);
-  else {
-    Name wrappedName;
-    wrappedName.append(invitationRoutingPrefix)
-      .append(ROUTING_PREFIX_SEPARATOR, 2)
-      .append(response->getName());
-
-    // _LOG_DEBUG("onInvitationResponded: prepare reply " << wrappedName);
-
-    shared_ptr<Data> wrappedData = make_shared<Data>(wrappedName);
-    wrappedData->setContent(response->wireEncode());
-    wrappedData->setFreshnessPeriod(time::milliseconds(1000));
-
-    m_keyChain.signByIdentity(*wrappedData, m_identity);
-    m_face->put(*wrappedData);
-  }
-
-  // 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));
-
-    Name chatPrefix;
-    chatPrefix.append(m_identity).append("CHRONOCHAT-DATA").append(invitation.getChatroom());
-
-    ChatDialog* chatDialog
-      = new ChatDialog(chatroomPrefix,
-                       chatPrefix,
-                       m_localPrefix,
-                       invitation.getChatroom(),
-                       m_nick,
-                       true);
-
-    chatDialog->addSyncAnchor(invitation);
-
-    addChatDialog(QString::fromStdString(invitation.getChatroom()), chatDialog);
-    chatDialog->show();
-  }
+  BOOST_ASSERT(it != m_chatDialogList.end());
+  it->second->addSyncAnchor(invitation);
 }
 
+
 void
 Controller::onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data)
 {
@@ -898,7 +676,6 @@
     if (deletedChat)
       delete deletedChat;
     m_chatDialogList.erase(it);
-    m_discoveryLogic.removeLocalChatroom(Name::Component(chatroomName.toStdString()));
 
     QAction* chatAction = m_chatActionList[chatroomName.toStdString()];
     QAction* closeAction = m_closeActionList[chatroomName.toStdString()];
@@ -928,35 +705,9 @@
 }
 
 void
-Controller::onInvitationInterest(const ndn::Name& prefix,
-                                 const ndn::Interest& interest,
-                                 size_t routingPrefixOffset)
-{
-  // _LOG_DEBUG("onInvitationInterest: " << interest.getName());
-  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::onRosterChanged(const chronos::ChatroomInfo& info)
 {
-  m_discoveryLogic.addLocalChatroom(info);
+
 }
 
 } // namespace chronos
diff --git a/src/controller.hpp b/src/controller.hpp
index 81b05a9..44e4801 100644
--- a/src/controller.hpp
+++ b/src/controller.hpp
@@ -24,14 +24,11 @@
 #include "browse-contact-dialog.hpp"
 #include "add-contact-panel.hpp"
 #include "chat-dialog.hpp"
-#include "chatroom-discovery-dialog.hpp"
 
 #ifndef Q_MOC_RUN
 #include "common.hpp"
-#include "contact-manager.hpp"
-#include "chatroom-discovery-logic.hpp"
-#include "validator-invitation.hpp"
-#include <ndn-cxx/security/key-chain.hpp>
+#include "invitation.hpp"
+#include "controller-backend.hpp"
 #endif
 
 namespace chronos {
@@ -41,7 +38,7 @@
   Q_OBJECT
 
 public: // public methods
-  Controller(shared_ptr<ndn::Face> face, QWidget* parent = 0);
+  Controller(QWidget* parent = 0);
 
   virtual
   ~Controller();
@@ -57,9 +54,6 @@
   initialize();
 
   void
-  setInvitationListener();
-
-  void
   loadConf();
 
   void
@@ -74,32 +68,9 @@
   void
   updateMenu();
 
-  void
-  onLocalPrefix(const Interest& interest, Data& data);
-
-  void
-  onLocalPrefixTimeout(const Interest& interest);
-
-  void
-  onInvitationInterestWrapper(const ndn::Name& prefix, const ndn::Interest& interest,
-                              size_t routingPrefixOffset);
-
-  void
-  onInvitationRegisterFailed(const Name& prefix, const std::string& failInfo);
-
-  void
-  onInvitationValidated(const shared_ptr<const Interest>& interest);
-
-  void
-  onInvitationValidationFailed(const shared_ptr<const Interest>& interest,
-                               std::string failureInfo);
-
   std::string
   getRandomString();
 
-  ndn::Name
-  getInvitationRoutingPrefix();
-
   void
   addChatDialog(const QString& chatroomName, ChatDialog* chatDialog);
 
@@ -108,6 +79,12 @@
 
 signals:
   void
+  shutdownBackend();
+
+  void
+  updateLocalPrefix();
+
+  void
   closeDBModule();
 
   void
@@ -129,6 +106,12 @@
   void
   discoverChatroomChanged(const chronos::ChatroomInfo& chatroomInfo, bool isAdd);
 
+  void
+  addChatroom(QString chatroomName);
+
+  void
+  removeChatroom(QString chatroomName);
+
 private slots:
   void
   onIdentityUpdated(const QString& identity);
@@ -137,9 +120,6 @@
   onIdentityUpdatedContinued();
 
   void
-  onContactIdListReady(const QStringList& list);
-
-  void
   onNickUpdated(const QString& nick);
 
   void
@@ -170,9 +150,6 @@
   onDirectAdd();
 
   void
-  onUpdateLocalPrefixAction();
-
-  void
   onMinimizeAction();
 
   void
@@ -182,7 +159,7 @@
   onStartChatroom(const QString& chatroom, bool secured);
 
   void
-  onInvitationResponded(const ndn::Name& invitationName, bool accepted);
+  onStartChatroom2(chronos::Invitation invitation, bool secured);
 
   void
   onShowChatMessage(const QString& chatroomName, const QString& from, const QString& data);
@@ -200,10 +177,6 @@
   onError(const QString& msg);
 
   void
-  onInvitationInterest(const ndn::Name& prefix, const ndn::Interest& interest,
-                       size_t routingPrefixOffset);
-
-  void
   onRosterChanged(const chronos::ChatroomInfo& info);
 
 private: // private member
@@ -211,16 +184,8 @@
   typedef std::map<std::string, ChatDialog*> ChatDialogList;
 
   // Communication
-  shared_ptr<ndn::Face> m_face;
   Name m_localPrefix;
   bool m_localPrefixDetected;
-  const ndn::RegisteredPrefixId* m_invitationListenerId;
-
-  // Contact Manager
-  ContactManager m_contactManager;
-
-  // Chatroom discovery
-  ChatroomDiscoveryLogic m_discoveryLogic;
 
   // Tray
   QAction*         m_startChatroom;
@@ -247,16 +212,14 @@
   BrowseContactDialog* m_browseContactDialog;
   AddContactPanel*     m_addContactPanel;
   ChatDialogList       m_chatDialogList;
-  ChatroomDiscoveryDialog* m_chatroomDiscoveryDialog;
 
   // Conf
   Name m_identity;
   std::string m_nick;
   QSqlDatabase m_db;
 
-  // Security related;
-  ndn::KeyChain m_keyChain;
-  ValidatorInvitation m_validator;
+  // Backend
+  ControllerBackend m_backend;
 };
 
 } // namespace chronos
diff --git a/src/invitation-dialog.cpp b/src/invitation-dialog.cpp
index 38665a8..717d515 100644
--- a/src/invitation-dialog.cpp
+++ b/src/invitation-dialog.cpp
@@ -31,14 +31,14 @@
 }
 
 void
-InvitationDialog::setInvitation(const std::string& alias,
-                                const std::string& chatroom,
-                                const Name& interestName)
+InvitationDialog::onInvitationReceived(QString alias, QString chatroom, Name interestName)
 {
-  std::string msg = alias;
   m_invitationInterest = interestName;
-  msg.append(" invites you to: ").append(chatroom);
-  ui->msgLabel->setText(QString::fromStdString(msg));
+
+  QString msg = QString("%1 invites you to chatroom\n %2 ").arg(alias).arg(chatroom);
+  ui->msgLabel->setText(msg);
+
+  show();
 }
 
 void
diff --git a/src/invitation-dialog.hpp b/src/invitation-dialog.hpp
index 0dab90f..b072656 100644
--- a/src/invitation-dialog.hpp
+++ b/src/invitation-dialog.hpp
@@ -33,15 +33,14 @@
 
   ~InvitationDialog();
 
-  void
-  setInvitation(const std::string& alias,
-                const std::string& chatroom,
-                const ndn::Name& invitationInterest);
-
 signals:
   void
   invitationResponded(const ndn::Name& invitationName, bool accepted);
 
+public slots:
+  void
+  onInvitationReceived(QString alias, QString chatroom, ndn::Name invitationInterest);
+
 private slots:
   void
   onOkClicked();
diff --git a/src/main.cpp b/src/main.cpp
index afa3665..137dd55 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -38,27 +38,13 @@
   }
 };
 
-void
-runIO(boost::asio::io_service& ioService)
-{
-  try {
-    ioService.run();
-  }
-  catch (std::runtime_error& e) {
-    std::cerr << e.what() << std::endl;
-  }
-}
-
 int main(int argc, char *argv[])
 {
   NewApp app(argc, argv);
 
-  ndn::shared_ptr<ndn::Face> face = ndn::make_shared<ndn::Face>();
-  chronos::Controller controller(face);
+  chronos::Controller controller;
 
   app.setQuitOnLastWindowClosed(false);
 
-  boost::thread(runIO, boost::ref(face->getIoService()));
-
   return app.exec();
 }