separate ChatDialog frontend & backend

Change-Id: I824e58579a9aaac0264561cc7ae3d4977d98a3bf
diff --git a/src/chat-dialog-backend.cpp b/src/chat-dialog-backend.cpp
new file mode 100644
index 0000000..87eed37
--- /dev/null
+++ b/src/chat-dialog-backend.cpp
@@ -0,0 +1,386 @@
+/* -*- 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 "chat-dialog-backend.hpp"
+
+#ifndef Q_MOC_RUN
+#include <ndn-cxx/util/io.hpp>
+#include "logging.h"
+#endif
+
+
+INIT_LOGGER("ChatDialogBackend");
+
+namespace chronos {
+
+static const time::milliseconds FRESHNESS_PERIOD(60000);
+static const time::seconds HELLO_INTERVAL(60);
+static const uint8_t ROUTING_HINT_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
+
+ChatDialogBackend::ChatDialogBackend(const Name& chatroomPrefix,
+                                     const Name& userChatPrefix,
+                                     const Name& routingPrefix,
+                                     const std::string& chatroomName,
+                                     const std::string& nick,
+                                     QObject* parent)
+  : QThread(parent)
+  , m_localRoutingPrefix(routingPrefix)
+  , m_chatroomPrefix(chatroomPrefix)
+  , m_userChatPrefix(userChatPrefix)
+  , m_chatroomName(chatroomName)
+  , m_nick(nick)
+  , m_scheduler(m_face.getIoService())
+{
+  updatePrefixes();
+}
+
+
+ChatDialogBackend::~ChatDialogBackend()
+{
+}
+
+// protected methods:
+void
+ChatDialogBackend::run()
+{
+  initializeSync();
+
+  m_face.processEvents();
+
+  std::cerr << "Bye!" << std::endl;
+}
+
+// private methods:
+void
+ChatDialogBackend::initializeSync()
+{
+  QMutexLocker locker(&mutex);
+
+  // if a SyncSocket is running, turn it off
+  if (static_cast<bool>(m_sock)) {
+    if (m_joined)
+      sendLeave();
+    m_sock.reset();
+
+    usleep(100000);
+  }
+
+  // create a new SyncSocket
+  m_sock = make_shared<chronosync::Socket>(m_chatroomPrefix,
+                                           m_routableUserChatPrefix,
+                                           ref(m_face),
+                                           bind(&ChatDialogBackend::processSyncUpdate, this, _1));
+
+  // schedule a new join event
+  m_scheduler.scheduleEvent(time::milliseconds(600),
+                            bind(&ChatDialogBackend::sendJoin, this));
+
+  // cancel existing hello event if it exists
+  if (static_cast<bool>(m_helloEventId)) {
+    m_scheduler.cancelEvent(m_helloEventId);
+    m_helloEventId.reset();
+  }
+}
+
+void
+ChatDialogBackend::processSyncUpdate(const std::vector<chronosync::MissingDataInfo>& updates)
+{
+  _LOG_DEBUG("<<< processing Tree Update");
+
+  if (updates.empty()) {
+    return;
+  }
+
+  std::vector<NodeInfo> nodeInfos;
+
+
+  for (int i = 0; i < updates.size(); i++) {
+    // update roster
+    if (m_roster.find(updates[i].session) == m_roster.end()) {
+      m_roster[updates[i].session].sessionPrefix = updates[i].session;
+      m_roster[updates[i].session].hasNick = false;
+    }
+
+    // fetch missing chat data
+    if (updates[i].high - updates[i].low < 3) {
+      for (chronosync::SeqNo seq = updates[i].low; seq <= updates[i].high; ++seq) {
+        m_sock->fetchData(updates[i].session, seq,
+                          bind(&ChatDialogBackend::processChatData, this, _1, true),
+                          2);
+        _LOG_DEBUG("<<< Fetching " << updates[i].session << "/" << seq);
+      }
+    }
+    else {
+      // There are too many msgs to fetch, let's just fetch the latest one
+      m_sock->fetchData(updates[i].session, updates[i].high,
+                        bind(&ChatDialogBackend::processChatData, this, _1, false),
+                        2);
+    }
+
+    // prepare notification to frontend
+    NodeInfo nodeInfo;
+    nodeInfo.sessionPrefix = QString::fromStdString(updates[i].session.toUri());
+    nodeInfo.seqNo = updates[i].high;
+    nodeInfos.push_back(nodeInfo);
+  }
+
+  // reflect the changes on GUI
+  emit syncTreeUpdated(nodeInfos,
+                       QString::fromStdString(getHexEncodedDigest(m_sock->getRootDigest())));
+}
+
+void
+ChatDialogBackend::processChatData(const ndn::shared_ptr<const ndn::Data>& data, bool needDisplay)
+{
+  SyncDemo::ChatMessage msg;
+
+  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);
+    return;
+  }
+
+  Name remoteSessionPrefix = data->getName().getPrefix(-1);
+
+  if (msg.type() == SyncDemo::ChatMessage::LEAVE) {
+    BackendRoster::iterator it = m_roster.find(remoteSessionPrefix);
+
+    if (it != m_roster.end()) {
+      // cancel timeout event
+      if (static_cast<bool>(it->second.timeoutEventId))
+        m_scheduler.cancelEvent(it->second.timeoutEventId);
+
+      // notify frontend to remove the remote session (node)
+      emit sessionRemoved(QString::fromStdString(remoteSessionPrefix.toUri()),
+                          QString::fromStdString(msg.from()),
+                          msg.timestamp());
+
+      // remove roster entry
+      m_roster.erase(remoteSessionPrefix);
+    }
+  }
+  else {
+    BackendRoster::iterator it = m_roster.find(remoteSessionPrefix);
+
+    if (it == m_roster.end()) {
+      // Should not happen
+      BOOST_ASSERT(false);
+    }
+
+    // If we haven't got any message from this session yet.
+    if (m_roster[remoteSessionPrefix].hasNick == false) {
+      m_roster[remoteSessionPrefix].userNick = msg.from();
+      m_roster[remoteSessionPrefix].hasNick = true;
+      emit sessionAdded(QString::fromStdString(remoteSessionPrefix.toUri()),
+                        QString::fromStdString(msg.from()),
+                        msg.timestamp());
+    }
+
+    // If we get a new nick for an existing session, update it.
+    if (m_roster[remoteSessionPrefix].userNick != msg.from()) {
+      m_roster[remoteSessionPrefix].userNick = msg.from();
+      emit nickUpdated(QString::fromStdString(remoteSessionPrefix.toUri()),
+                       QString::fromStdString(msg.from()));
+    }
+
+    // If a timeout event has been scheduled, cancel it.
+    if (static_cast<bool>(it->second.timeoutEventId))
+      m_scheduler.cancelEvent(it->second.timeoutEventId);
+
+    // (Re)schedule another timeout event after 3 HELLO_INTERVAL;
+    it->second.timeoutEventId =
+      m_scheduler.scheduleEvent(HELLO_INTERVAL * 3,
+                                bind(&ChatDialogBackend::remoteSessionTimeout,
+                                     this, remoteSessionPrefix));
+
+    // If chat message, notify the frontend
+    if (msg.type() == SyncDemo::ChatMessage::CHAT)
+      emit chatMessageReceived(QString::fromStdString(msg.from()),
+                               QString::fromStdString(msg.data()),
+                               msg.timestamp());
+
+    // Notify frontend to plot notification on DigestTree.
+    emit messageReceived(QString::fromStdString(remoteSessionPrefix.toUri()));
+  }
+}
+
+void
+ChatDialogBackend::remoteSessionTimeout(const Name& sessionPrefix)
+{
+  time_t timestamp =
+    static_cast<time_t>(time::toUnixTimestamp(time::system_clock::now()).count() / 1000);
+
+  // notify frontend
+  emit sessionRemoved(QString::fromStdString(sessionPrefix.toUri()),
+                      QString::fromStdString(m_roster[sessionPrefix].userNick),
+                      timestamp);
+
+  // remove roster entry
+  m_roster.erase(sessionPrefix);
+}
+
+void
+ChatDialogBackend::sendMsg(SyncDemo::ChatMessage& msg)
+{
+  // send msg
+  ndn::OBufferStream os;
+  msg.SerializeToOstream(&os);
+
+  if (!msg.IsInitialized()) {
+    _LOG_DEBUG("Errrrr.. msg was not probally initialized " << __FILE__ <<
+               ":" << __LINE__ << ". what is happening?");
+    abort();
+  }
+
+  uint64_t nextSequence = m_sock->getLogic().getSeqNo() + 1;
+
+  m_sock->publishData(os.buf()->buf(), os.buf()->size(), FRESHNESS_PERIOD);
+
+  std::vector<NodeInfo> nodeInfos;
+  NodeInfo nodeInfo = {QString::fromStdString(m_routableUserChatPrefix.toUri()),
+                       nextSequence};
+  nodeInfos.push_back(nodeInfo);
+
+  emit syncTreeUpdated(nodeInfos,
+                       QString::fromStdString(getHexEncodedDigest(m_sock->getRootDigest())));
+}
+
+void
+ChatDialogBackend::sendJoin()
+{
+  m_joined = true;
+
+  SyncDemo::ChatMessage msg;
+  prepareControlMessage(msg, SyncDemo::ChatMessage::JOIN);
+  sendMsg(msg);
+
+  m_helloEventId = m_scheduler.scheduleEvent(HELLO_INTERVAL,
+                                             bind(&ChatDialogBackend::sendHello, this));
+
+  emit sessionAdded(QString::fromStdString(m_routableUserChatPrefix.toUri()),
+                    QString::fromStdString(msg.from()),
+                    msg.timestamp());
+}
+
+void
+ChatDialogBackend::sendHello()
+{
+  SyncDemo::ChatMessage msg;
+  prepareControlMessage(msg, SyncDemo::ChatMessage::HELLO);
+  sendMsg(msg);
+
+  m_helloEventId = m_scheduler.scheduleEvent(HELLO_INTERVAL,
+                                             bind(&ChatDialogBackend::sendHello, this));
+}
+
+void
+ChatDialogBackend::sendLeave()
+{
+  SyncDemo::ChatMessage msg;
+  prepareControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
+  sendMsg(msg);
+
+  usleep(5000);
+  m_joined = false;
+}
+
+void
+ChatDialogBackend::prepareControlMessage(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::toUnixTimestamp(time::system_clock::now()).count() / 1000);
+  msg.set_timestamp(seconds);
+  msg.set_type(type);
+}
+
+void
+ChatDialogBackend::prepareChatMessage(const QString& text,
+                                      time_t timestamp,
+                                      SyncDemo::ChatMessage &msg)
+{
+  msg.set_from(m_nick);
+  msg.set_to(m_chatroomName);
+  msg.set_data(text.toStdString());
+  msg.set_timestamp(timestamp);
+  msg.set_type(SyncDemo::ChatMessage::CHAT);
+}
+
+void
+ChatDialogBackend::updatePrefixes()
+{
+  m_routableUserChatPrefix.clear();
+
+  if (m_localRoutingPrefix.isPrefixOf(m_userChatPrefix))
+    m_routableUserChatPrefix = m_userChatPrefix;
+  else
+    m_routableUserChatPrefix.append(m_localRoutingPrefix)
+      .append(ROUTING_HINT_SEPARATOR, 2)
+      .append(m_userChatPrefix);
+
+  emit chatPrefixChanged(m_routableUserChatPrefix);
+}
+
+std::string
+ChatDialogBackend::getHexEncodedDigest(ndn::ConstBufferPtr digest)
+{
+  std::stringstream os;
+
+  CryptoPP::StringSource(digest->buf(), digest->size(), true,
+                         new CryptoPP::HexEncoder(new CryptoPP::FileSink(os), false));
+  return os.str();
+}
+
+
+// public slots:
+void
+ChatDialogBackend::sendChatMessage(QString text, time_t timestamp)
+{
+  SyncDemo::ChatMessage msg;
+  prepareChatMessage(text, timestamp, msg);
+  sendMsg(msg);
+
+  emit chatMessageReceived(QString::fromStdString(msg.from()),
+                           QString::fromStdString(msg.data()),
+                           msg.timestamp());
+}
+
+void
+ChatDialogBackend::updateRoutingPrefix(const QString& localRoutingPrefix)
+{
+  Name newLocalRoutingPrefix(localRoutingPrefix.toStdString());
+
+  if (!newLocalRoutingPrefix.empty() && newLocalRoutingPrefix != m_localRoutingPrefix) {
+    // Update localPrefix
+    m_localRoutingPrefix = newLocalRoutingPrefix;
+
+    updatePrefixes();
+
+    initializeSync();
+  }
+}
+
+void
+ChatDialogBackend::shutdown()
+{
+  m_face.getIoService().stop();
+}
+
+} // namespace chronos
+
+#if WAF
+#include "chat-dialog-backend.moc"
+// #include "chat-dialog-backend.cpp.moc"
+#endif
diff --git a/src/chat-dialog-backend.hpp b/src/chat-dialog-backend.hpp
new file mode 100644
index 0000000..eda4094
--- /dev/null
+++ b/src/chat-dialog-backend.hpp
@@ -0,0 +1,156 @@
+/* -*- 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_CHAT_DIALOG_BACKEND_HPP
+#define CHRONOCHAT_CHAT_DIALOG_BACKEND_HPP
+
+#include <QThread>
+#include <QMutex>
+
+#ifndef Q_MOC_RUN
+#include "common.hpp"
+#include "chatroom-info.hpp"
+#include "chatbuf.pb.h"
+#include <socket.hpp>
+#endif
+
+namespace chronos {
+
+class NodeInfo {
+public:
+  QString sessionPrefix;
+  chronosync::SeqNo seqNo;
+};
+
+class UserInfo {
+public:
+  ndn::Name sessionPrefix;
+  bool hasNick;
+  std::string userNick;
+  ndn::EventId timeoutEventId;
+};
+
+class ChatDialogBackend : public QThread
+{
+  Q_OBJECT
+
+public:
+  ChatDialogBackend(const Name& chatroomPrefix,
+                    const Name& userChatPrefix,
+                    const Name& routingPrefix,
+                    const std::string& chatroomName,
+                    const std::string& nick,
+                    QObject* parent = 0);
+
+  ~ChatDialogBackend();
+
+protected:
+  void
+  run();
+
+private:
+  void
+  initializeSync();
+
+  void
+  processSyncUpdate(const std::vector<chronosync::MissingDataInfo>& updates);
+
+  void
+  processChatData(const ndn::shared_ptr<const ndn::Data>& data, bool needDisplay);
+
+  void
+  remoteSessionTimeout(const Name& sessionPrefix);
+
+  void
+  sendMsg(SyncDemo::ChatMessage& msg);
+
+  void
+  sendJoin();
+
+  void
+  sendHello();
+
+  void
+  sendLeave();
+
+  void
+  prepareControlMessage(SyncDemo::ChatMessage& msg,
+                        SyncDemo::ChatMessage::ChatMessageType type);
+
+  void
+  prepareChatMessage(const QString& text,
+                     time_t timestamp,
+                     SyncDemo::ChatMessage &msg);
+
+  void
+  updatePrefixes();
+
+  std::string
+  getHexEncodedDigest(ndn::ConstBufferPtr digest);
+
+signals:
+  void
+  syncTreeUpdated(std::vector<chronos::NodeInfo> updates, QString digest);
+
+  void
+  chatMessageReceived(QString nick, QString text, time_t timestamp);
+
+  void
+  sessionAdded(QString sessionPrefix, QString nick, time_t timestamp);
+
+  void
+  sessionRemoved(QString sessionPrefix, QString nick, time_t timestamp);
+
+  void
+  nickUpdated(QString sessionPrefix, QString nick);
+
+  void
+  messageReceived(QString sessionPrefix);
+
+  void
+  chatPrefixChanged(ndn::Name newChatPrefix);
+
+public slots:
+  void
+  sendChatMessage(QString text, time_t timestamp);
+
+  void
+  updateRoutingPrefix(const QString& localRoutingPrefix);
+
+  void
+  shutdown();
+
+private:
+  typedef std::map<ndn::Name, UserInfo> BackendRoster;
+
+  ndn::Face m_face;
+
+  Name m_localRoutingPrefix;             // routable local prefix
+  Name m_chatroomPrefix;                 // chatroom sync prefix
+  Name m_userChatPrefix;                 // user chat prefix
+  Name m_routableUserChatPrefix;         // routable user chat prefix
+
+  std::string m_chatroomName;            // chatroom name
+  std::string m_nick;                    // user nick
+
+  shared_ptr<chronosync::Socket> m_sock; // SyncSocket
+
+  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
+};
+
+} // namespace chronos
+
+#endif // CHRONOCHAT_CHAT_DIALOG_BACKEND_HPP
diff --git a/src/chat-dialog.cpp b/src/chat-dialog.cpp
index 0079f4f..a475c16 100644
--- a/src/chat-dialog.cpp
+++ b/src/chat-dialog.cpp
@@ -17,99 +17,100 @@
 #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-cxx/util/random.hpp>
-#include <ndn-cxx/encoding/buffer-stream.hpp>
-#include "cryptopp.hpp"
-#include <queue>
-#include "logging.h"
-
-#define SECURITY_ENABLED false
-#endif
-
-
-// INIT_LOGGER("ChatDialog");
-
-Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
-Q_DECLARE_METATYPE(ndn::shared_ptr<const ndn::Data>)
-Q_DECLARE_METATYPE(ndn::Interest)
-Q_DECLARE_METATYPE(size_t)
-
+Q_DECLARE_METATYPE(ndn::Name)
+Q_DECLARE_METATYPE(time_t)
+Q_DECLARE_METATYPE(std::vector<chronos::NodeInfo>)
 
 namespace chronos {
 
-using std::vector;
-using std::string;
-using std::map;
-using std::queue;
+static const Name PRIVATE_PREFIX("/private/local");
+static const uint8_t ROUTING_HINT_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
 
-using ndn::IdentityCertificate;
-using ndn::SecRuleRelative;
-using ndn::Face;
-using ndn::OBufferStream;
-using ndn::OnDataValidated;
-using ndn::OnDataValidationFailed;
-
-
-static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
-static const uint8_t CHRONOS_RP_SEPARATOR[2] = {0xF0, 0x2E}; // %F0.
-
-ChatDialog::ChatDialog(ContactManager* contactManager,
-                       shared_ptr<Face> face,
-                       const IdentityCertificate& myCertificate,
-                       const Name& chatroomPrefix,
-                       const Name& localPrefix,
+ChatDialog::ChatDialog(const Name& chatroomPrefix,
+                       const Name& userChatPrefix,
+                       const Name& routingPrefix,
+                       const std::string& chatroomName,
                        const std::string& nick,
-                       bool withSecurity,
+                       bool isSecured,
                        QWidget* parent)
   : QDialog(parent)
   , ui(new Ui::ChatDialog)
-  , m_contactManager(contactManager)
-  , m_face(face)
-  , m_myCertificate(myCertificate)
-  , m_chatroomName(chatroomPrefix.get(-1).toUri())
-  , m_chatroomPrefix(chatroomPrefix)
-  , m_localPrefix(localPrefix)
-  , m_useRoutablePrefix(false)
-  , m_nick(nick)
-  , m_lastMsgTime(time::toUnixTimestamp(time::system_clock::now()).count())
-  , m_joined(false)
-  , m_sock(NULL)
-  , m_session(static_cast<uint64_t>(time::toUnixTimestamp(time::system_clock::now()).count()))
-  , m_inviteListDialog(new InviteListDialog)
-  //ymj
-  //, m_trustModel(withSecurity)
+  , m_backend(chatroomPrefix, userChatPrefix, routingPrefix, chatroomName, nick)
+  , m_chatroomName(chatroomName)
+  , m_nick(nick.c_str())
+  , m_isSecured(isSecured)
 {
-  qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
-  qRegisterMetaType<ndn::shared_ptr<const ndn::Data> >("ndn.DataPtr");
-  qRegisterMetaType<ndn::Interest>("ndn.Interest");
-  qRegisterMetaType<size_t>("size_t");
+  qRegisterMetaType<ndn::Name>("ndn::Name");
+  qRegisterMetaType<time_t>("time_t");
+  qRegisterMetaType<std::vector<chronos::NodeInfo> >("std::vector<chronos::NodeInfo>");
 
   m_scene = new DigestTreeScene(this);
   m_trustScene = new TrustTreeScene(this);
   m_rosterModel = new QStringListModel(this);
-  m_timer = new QTimer(this);
 
   ui->setupUi(this);
+
   ui->syncTreeViewer->setScene(m_scene);
   m_scene->setSceneRect(m_scene->itemsBoundingRect());
   ui->syncTreeViewer->hide();
+
   ui->trustTreeViewer->setScene(m_trustScene);
   m_trustScene->setSceneRect(m_trustScene->itemsBoundingRect());
   ui->trustTreeViewer->hide();
+
   ui->listView->setModel(m_rosterModel);
 
-  m_identity =
-    IdentityCertificate::certificateNameToPublicKeyName(m_myCertificate.getName()).getPrefix(-1);
+  Name routablePrefix;
 
-  updatePrefix();
+  if (routingPrefix.isPrefixOf(userChatPrefix))
+    routablePrefix = userChatPrefix;
+  else
+    routablePrefix.append(routingPrefix)
+      .append(ROUTING_HINT_SEPARATOR, 2)
+      .append(userChatPrefix);
 
-  updateLabels();
+  updateLabels(routablePrefix);
 
-  m_scene->setCurrentPrefix(QString(m_localChatPrefix.toUri().c_str()));
+  QStringList roster;
+  roster << "- " + m_nick;
+  m_rosterModel->setStringList(roster);
+
+  // When backend receives a sync update, notify frontend to update sync tree
+  connect(&m_backend, SIGNAL(syncTreeUpdated(std::vector<chronos::NodeInfo>, QString)),
+          this,       SLOT(updateSyncTree(std::vector<chronos::NodeInfo>, QString)));
+
+  // When backend receives a new chat message, notify frontent to print it out.
+  connect(&m_backend, SIGNAL(chatMessageReceived(QString, QString, time_t)),
+          this,       SLOT(receiveChatMessage(QString, QString, time_t)));
+
+  // When backend detects a new session, notify frontend to print the message.
+  connect(&m_backend, SIGNAL(sessionAdded(QString, QString, time_t)),
+          this,       SLOT(addSession(QString, QString, time_t)));
+
+  // When backend detects a deleted session, notify frontend to print the message.
+  connect(&m_backend, SIGNAL(sessionRemoved(QString, QString, time_t)),
+          this,       SLOT(removeSession(QString, QString, time_t)));
+
+  // When backend detects nick changed, notify frontend to print the new nick
+  connect(&m_backend, SIGNAL(nickUpdated(QString, QString)),
+          this,       SLOT(updateNick(QString, QString)));
+
+  // When backend receives a new message, notify frontend to print notification
+  connect(&m_backend, SIGNAL(messageReceived(QString)),
+          this,       SLOT(receiveMessage(QString)));
+
+  // When backend updates prefix, notify frontend to update labels.
+  connect(&m_backend, SIGNAL(chatPrefixChanged(ndn::Name)),
+          this,       SLOT(updateLabels(ndn::Name)));
+
+  // When frontend gets a message to send, notify backend.
+  connect(this,       SIGNAL(msgToSent(QString, time_t)),
+          &m_backend, SLOT(sendChatMessage(QString, time_t)));
+
+  // When frontend gets a shutdown command, notify backend.
+  connect(this,       SIGNAL(shutdownBackend()),
+          &m_backend, SLOT(shutdown()));
+
   m_scene->plot("Empty");
 
   connect(ui->lineEdit, SIGNAL(returnPressed()),
@@ -118,123 +119,23 @@
           this, SLOT(onSyncTreeButtonPressed()));
   connect(ui->trustTreeButton, SIGNAL(pressed()),
           this, SLOT(onTrustTreeButtonPressed()));
-  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::shared_ptr<const ndn::Data>&, bool, bool)),
-          this, SLOT(onProcessData(const ndn::shared_ptr<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::shared_ptr<const ndn::Data>&,
-                             size_t, bool)),
-          this, SLOT(onReply(const ndn::Interest&,
-                             const ndn::shared_ptr<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::shared_ptr<const ndn::Data>&)),
-          this, SLOT(onIntroCert(const ndn::Interest&, const ndn::shared_ptr<const ndn::Data>&)));
-  connect(this, SIGNAL(introCertTimeout(const ndn::Interest&, int, const QString&)),
-          this, SLOT(onIntroCertTimeout(const ndn::Interest&, int, const QString&)));
+  disableSyncTreeDisplay();
+  QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
 
-  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);
-    ui->trustTreeButton->setEnabled(true);
-
-    connect(ui->inviteButton, SIGNAL(clicked()),
-            this, SLOT(onInviteListDialogRequested()));
-    connect(m_inviteListDialog, SIGNAL(sendInvitation(const QString&)),
-            this, SLOT(onSendInvitation(const QString&)));
-    connect(this, SIGNAL(waitForContactList()),
-            m_contactManager, SLOT(onWaitForContactList()));
-    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&)));
-
-    m_trustModel = ChatroomInfo::TRUST_MODEL_WEBOFTRUST;
-  }
-  else
-    m_trustModel = ChatroomInfo::TRUST_MODEL_NONE;
-
-  initializeSync();
+  m_backend.start();
 }
 
 
 ChatDialog::~ChatDialog()
 {
-  if (SECURITY_ENABLED) {
-    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)
-{
-  // _LOG_DEBUG("Add sync anchor from invitation");
-  // Add inviter certificate as trust anchor.
-  m_sock->addParticipant(invitation.getInviterCertificate());
-  plotTrustTree();
-
-  // 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(const string& prefix)
-{
-  // _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
-}
-
-// protected methods:
 void
 ChatDialog::closeEvent(QCloseEvent *e)
 {
+  // When close button is clicked, do not close the dialog immediately.
+
   QMessageBox::information(this, tr("ChronoChat"),
                            tr("The chatroom will keep running in the "
                               "system tray. To close the chatroom, "
@@ -270,355 +171,28 @@
   fitView();
 }
 
+shared_ptr<ChatroomInfo>
+ChatDialog::getChatroomInfo()
+{
+  shared_ptr<ChatroomInfo> chatroomInfo = make_shared<ChatroomInfo>();
+
+  chatroomInfo->setName(Name::Component(m_chatroomName));
+
+  QStringList prefixList = m_scene->getRosterPrefixList();
+  for(QStringList::iterator it = prefixList.begin();
+      it != prefixList.end(); ++it ) {
+    Name participant = Name(it->toStdString()).getPrefix(-3);
+    chatroomInfo->addParticipant(participant);
+  }
+
+  if (m_isSecured)
+    chatroomInfo->setTrustModel(ChatroomInfo::TRUST_MODEL_WEBOFTRUST);
+  else
+    chatroomInfo->setTrustModel(ChatroomInfo::TRUST_MODEL_NONE);
+  return chatroomInfo;
+}
+
 // 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 (SECURITY_ENABLED) {
-    if (static_cast<bool>(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 (static_cast<bool>(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);
-  disableSyncTreeDisplay();
-  QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
-}
-
-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);
-  // _LOG_DEBUG("sendInvitation: " << interest.getName());
-  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)
-{
-  // _LOG_DEBUG("ChatDialog::replyWrapper");
-  emit reply(interest, data.shared_from_this(), routablePrefixOffset, isIntroducer);
-  // _LOG_DEBUG("OK?");
-}
-
-void
-ChatDialog::replyTimeoutWrapper(const Interest& interest,
-                                size_t routablePrefixOffset)
-{
-  // _LOG_DEBUG("ChatDialog::replyTimeoutWrapper");
-  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);
-  plotTrustTree();
-
-  // 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);
-
-    // _LOG_DEBUG("onIntroCertList: to fetch " << certName);
-
-    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.shared_from_this());
-}
-
-void
-ChatDialog::introCertTimeoutWrapper(const Interest& interest, int retry, const QString& msg)
-{
-  emit introCertTimeout(interest, retry, msg);
-}
-
-void
-ChatDialog::onCertListInterest(const ndn::Name& prefix, const ndn::Interest& interest)
-{
-  vector<Name> certNameList;
-  m_sock->getIntroCertNames(certNameList);
-
-  Chronos::IntroCertListMsg msg;
-
-  for (vector<Name>::const_iterator it = certNameList.begin(); it != certNameList.end(); it++) {
-    Name certName;
-    certName.append(m_certSinglePrefix).append(*it);
-    msg.add_certname(certName.toUri());
-  }
-  OBufferStream os;
-  msg.SerializeToOstream(&os);
-
-  shared_ptr<Data> data = make_shared<Data>(interest.getName());
-  data->setContent(os.buf());
-  m_keyChain.sign(*data, m_myCertificate.getName());
-
-  m_face->put(*data);
-}
-
-void
-ChatDialog::onCertListRegisterFailed(const ndn::Name& prefix, const std::string& msg)
-{
-  _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
-}
-
-void
-ChatDialog::onCertSingleInterest(const Name& prefix, const Interest& interest)
-{
-  try {
-    Name certName = interest.getName().getSubName(prefix.size());
-    const Sync::IntroCertificate& introCert = m_sock->getIntroCertificate(certName);
-
-    shared_ptr<Data> data = make_shared<Data>(interest.getName());
-    data->setContent(introCert.wireEncode());
-    m_keyChain.sign(*data,  m_myCertificate.getName());
-    m_face->put(*data);
-  }
-  catch(Sync::SyncSocket::Error& e) {
-    return;
-  }
-}
-
-void
-ChatDialog::onCertSingleRegisterFailed(const Name& prefix, const std::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();
-  }
-  uint64_t nextSequence = m_sock->getNextSeq();
-  m_sock->publishData(os.buf()->buf(), os.buf()->size(), FRESHNESS);
-
-  m_lastMsgTime = time::toUnixTimestamp(time::system_clock::now()).count();
-
-  Sync::MissingDataInfo mdi = {m_localChatPrefix.toUri(),
-                               Sync::SeqNo(0),
-                               Sync::SeqNo(nextSequence)};
-  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::disableSyncTreeDisplay()
 {
   ui->syncTreeButton->setEnabled(false);
@@ -627,130 +201,61 @@
 }
 
 void
-ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
+ChatDialog::appendChatMessage(const QString& nick, const QString& text, time_t timestamp)
 {
-  boost::recursive_mutex::scoped_lock lock(m_msgMutex);
+  QTextCharFormat nickFormat;
+  nickFormat.setForeground(Qt::darkGreen);
+  nickFormat.setFontWeight(QFont::Bold);
+  nickFormat.setFontUnderline(true);
+  nickFormat.setUnderlineColor(Qt::gray);
 
-  if (msg.type() == SyncDemo::ChatMessage::CHAT) {
-    if (!msg.has_data()) {
-      return;
-    }
+  // Print who & when
+  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(nick);
+  QTextTableCell fromCell = table->cellAt(0, 0);
+  fromCell.setFormat(nickFormat);
+  fromCell.firstCursorPosition().insertText(from);
+  printTimeInCell(table, timestamp);
 
-    if (msg.from().empty() || msg.data().empty()) {
-      return;
-    }
+  // Print what
+  QTextCursor nextCursor(ui->textEdit->textCursor());
+  nextCursor.movePosition(QTextCursor::End);
+  table = nextCursor.insertTable(1, 1, tableFormat);
+  table->cellAt(0, 0).firstCursorPosition().insertText(text);
 
-    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);
-  }
+  // Popup notification
+  showMessage(from, text);
 
   QScrollBar *bar = ui->textEdit->verticalScrollBar();
   bar->setValue(bar->maximum());
 }
 
 void
-ChatDialog::processRemove(QString prefix)
+ChatDialog::appendControlMessage(const QString& nick,
+                                 const QString& action,
+                                 time_t timestamp)
 {
-  // _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
+  QTextCharFormat nickFormat;
+  nickFormat.setForeground(Qt::gray);
+  nickFormat.setFontWeight(QFont::Bold);
+  nickFormat.setFontUnderline(true);
+  nickFormat.setUnderlineColor(Qt::gray);
 
-  bool removed = m_scene->removeNode(prefix);
-  if (removed) {
-    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-    m_scene->plot(m_sock->getRootDigest().c_str());
-  }
-}
+  QTextCursor cursor(ui->textEdit->textCursor());
+  cursor.movePosition(QTextCursor::End);
+  QTextTableFormat tableFormat;
+  tableFormat.setBorder(0);
+  QTextTable *table = cursor.insertTable(1, 2, tableFormat);
 
-Name
-ChatDialog::getInviteeRoutablePrefix(const Name& invitee)
-{
-  return 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::toUnixTimestamp(time::system_clock::now()).count()/1000);
-  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::toUnixTimestamp(time::system_clock::now()).count()/1000);
-  msg.set_timestamp(seconds);
-  msg.set_type(type);
+  QString controlMsg = QString("%1 %2  ").arg(nick).arg(action);
+  QTextTableCell fromCell = table->cellAt(0, 0);
+  fromCell.setFormat(nickFormat);
+  fromCell.firstCursorPosition().insertText(controlMsg);
+  printTimeInCell(table, timestamp);
 }
 
 QString
@@ -788,21 +293,6 @@
   timeCell.firstCursorPosition().insertText(formatTime(timestamp));
 }
 
-string
-ChatDialog::getRandomString()
-{
-  uint32_t r = ndn::random::generateWord32();
-  std::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)
 {
@@ -814,7 +304,6 @@
 void
 ChatDialog::fitView()
 {
-  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
   QRectF rect = m_scene->itemsBoundingRect();
   m_scene->setSceneRect(rect);
   ui->syncTreeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
@@ -824,200 +313,8 @@
   ui->trustTreeViewer->fitInView(m_trustScene->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();
-}
-
-void
-ChatDialog::getTree(TrustTreeNodeList& nodeList)
-{
-  typedef map<Name, shared_ptr<TrustTreeNode> > NodeMap;
-
-  vector<Name> certNameList;
-  NodeMap nodeMap;
-
-  m_sock->getIntroCertNames(certNameList);
-
-  for (vector<Name>::const_iterator it = certNameList.begin(); it != certNameList.end(); it++) {
-    Name introducerCertName;
-    Name introduceeCertName;
-
-    introducerCertName.wireDecode(it->get(-2).blockFromValue());
-    introduceeCertName.wireDecode(it->get(-3).blockFromValue());
-
-    Name introducerName =
-      IdentityCertificate::certificateNameToPublicKeyName(introducerCertName).getPrefix(-1);
-    Name introduceeName =
-      IdentityCertificate::certificateNameToPublicKeyName(introduceeCertName).getPrefix(-1);
-
-    NodeMap::iterator introducerIt = nodeMap.find(introducerName);
-    if (introducerIt == nodeMap.end()) {
-      shared_ptr<TrustTreeNode> introducerNode(new TrustTreeNode(introducerName));
-      nodeMap[introducerName] = introducerNode;
-    }
-    shared_ptr<TrustTreeNode> erNode = nodeMap[introducerName];
-
-    NodeMap::iterator introduceeIt = nodeMap.find(introduceeName);
-    if (introduceeIt == nodeMap.end()) {
-      shared_ptr<TrustTreeNode> introduceeNode(new TrustTreeNode(introduceeName));
-      nodeMap[introduceeName] = introduceeNode;
-    }
-    shared_ptr<TrustTreeNode> eeNode = nodeMap[introduceeName];
-
-    erNode->addIntroducee(eeNode);
-    eeNode->addIntroducer(erNode);
-  }
-
-  nodeList.clear();
-  queue<shared_ptr<TrustTreeNode> > nodeQueue;
-
-  NodeMap::iterator nodeIt = nodeMap.find(m_identity);
-  if (nodeIt == nodeMap.end())
-    return;
-
-  nodeQueue.push(nodeIt->second);
-  nodeIt->second->setLevel(0);
-  while (!nodeQueue.empty()) {
-    shared_ptr<TrustTreeNode>& node = nodeQueue.front();
-    node->setVisited();
-
-    TrustTreeNodeList& introducees = node->getIntroducees();
-    for (TrustTreeNodeList::iterator eeIt = introducees.begin();
-         eeIt != introducees.end(); eeIt++) {
-      // _LOG_DEBUG("introducee: " << (*eeIt)->name() <<
-      //            " visited: " << std::boolalpha << (*eeIt)->visited());
-      if (!(*eeIt)->visited()) {
-        nodeQueue.push(*eeIt);
-        (*eeIt)->setLevel(node->level()+1);
-      }
-    }
-
-    nodeList.push_back(node);
-    nodeQueue.pop();
-  }
-}
-
-void
-ChatDialog::plotTrustTree()
-{
-  TrustTreeNodeList nodeList;
-
-  getTree(nodeList);
-  {
-    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
-    m_trustScene->plotTrustTree(nodeList);
-    fitView();
-  }
-}
-
-shared_ptr<ChatroomInfo>
-ChatDialog::getChatroomInfo() const
-{
-  shared_ptr<ChatroomInfo> chatroom = make_shared<ChatroomInfo>();
-  chatroom->setName(Name::Component(m_chatroomName));
-
-  Roster roster = m_scene->getRosterFull();
-  Roster_iterator it = roster.begin();
-
-  for(it = roster.begin(); it != roster.end(); ++it )
-  {
-    Name participant = Name(it.key().toStdString()).getPrefix(-3);
-    chatroom->addParticipant(participant);
-  }
-
-  chatroom->setTrustModel(m_trustModel);
-  return chatroom;
-}
-
-
 // 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);
-      disableSyncTreeDisplay();
-      QTimer::singleShot(2200, this, SLOT(enableSyncTreeDisplay()));
-    }
-    else
-      initializeSync();
-  }
-  else
-    if (m_sock == NULL)
-      initializeSync();
-
-  fitView();
-}
-
-void
 ChatDialog::onShow()
 {
   this->show();
@@ -1026,42 +323,104 @@
 }
 
 void
-ChatDialog::onClose()
+ChatDialog::shutdown()
 {
+  if (m_backend.isRunning()) {
+    emit shutdownBackend();
+    m_backend.wait();
+  }
   hide();
   emit closeChatDialog(QString::fromStdString(m_chatroomName));
 }
 
-
 // private slots:
 void
+ChatDialog::updateSyncTree(std::vector<chronos::NodeInfo> updates, QString rootDigest)
+{
+  m_scene->processSyncUpdate(updates, rootDigest);
+}
+
+void
+ChatDialog::receiveChatMessage(QString nick, QString text, time_t timestamp)
+{
+  appendChatMessage(nick, text, timestamp);
+}
+
+void
+ChatDialog::addSession(QString sessionPrefix, QString nick, time_t timestamp)
+{
+  appendControlMessage(nick, "enters room", timestamp);
+  m_scene->updateNick(sessionPrefix, nick);
+  m_rosterModel->setStringList(m_scene->getRosterList());
+}
+
+void
+ChatDialog::removeSession(QString sessionPrefix, QString nick, time_t timestamp)
+{
+  appendControlMessage(nick, "leaves room", timestamp);
+  m_scene->removeNode(sessionPrefix);
+  m_rosterModel->setStringList(m_scene->getRosterList());
+}
+
+void
+ChatDialog::updateNick(QString sessionPrefix, QString nick)
+{
+  m_scene->updateNick(sessionPrefix, nick);
+  m_rosterModel->setStringList(m_scene->getRosterList());
+}
+
+void
+ChatDialog::receiveMessage(QString sessionPrefix)
+{
+  m_scene->messageReceived(sessionPrefix);
+}
+
+void
+ChatDialog::updateLabels(Name newChatPrefix)
+{
+  // Reset DigestTree
+  m_scene->clearAll();
+  m_scene->plot("Empty");
+
+  // Display chatroom name
+  QString chatroomName = QString("Chatroom: %1").arg(QString::fromStdString(m_chatroomName));
+  ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
+  ui->infoLabel->setText(chatroomName);
+
+  // Display chat message prefix
+  QString chatPrefix;
+  if (PRIVATE_PREFIX.isPrefixOf(newChatPrefix)) {
+    chatPrefix =
+      QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n"
+              "<Prefix = %1>")
+      .arg(QString::fromStdString(newChatPrefix.toUri()));
+    ui->prefixLabel->setStyleSheet(
+      "QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
+  }
+  else {
+    chatPrefix = QString("<Prefix = %1>")
+      .arg(QString::fromStdString(newChatPrefix.toUri()));
+    ui->prefixLabel->setStyleSheet(
+      "QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
+  }
+  ui->prefixLabel->setText(chatPrefix);
+}
+
+void
 ChatDialog::onReturnPressed()
 {
   QString text = ui->lineEdit->text();
+
   if (text.isEmpty())
     return;
 
   ui->lineEdit->clear();
 
-  if (text.startsWith("boruoboluomi")) {
-    summonReaper ();
-    // reapButton->show();
-    fitView();
-    return;
-  }
+  time_t timestamp =
+    static_cast<time_t>(time::toUnixTimestamp(time::system_clock::now()).count() / 1000);
+  // appendChatMessage(m_nick, text, timestamp);
 
-  if (text.startsWith("minimanihong")) {
-    // reapButton->hide();
-    fitView();
-    return;
-  }
-
-  SyncDemo::ChatMessage msg;
-  formChatMessage(text, msg);
-
-  appendMessage(msg);
-
-  sendMsg(msg);
+  emit msgToSent(text, timestamp);
 
   fitView();
 }
@@ -1096,252 +455,11 @@
   fitView();
 }
 
-void
-ChatDialog::onProcessData(const ndn::shared_ptr<const ndn::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;
-  }
-
-  //std::cout << "onProcessData: " << show << std::endl;
-  //std::cout << "onProcessData: " << corrupted << std::endl;
-
-  // 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
-    string prefix = data->getName().getPrefix(-2).toUri();
-    // _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()) {
-    string nick = it.next().toStdString();
-    if (nick.empty())
-      continue;
-
-    SyncDemo::ChatMessage msg;
-    formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
-    msg.set_from(nick);
-    appendMessage(msg);
-  }
-  plotTrustTree();
-
-  emit rosterChanged(*getChatroomInfo());
-}
-
-void
-ChatDialog::onInviteListDialogRequested()
-{
-  emit waitForContactList();
-  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::toUnixTimestamp(time::system_clock::now()).count();
-  int elapsed = (now - m_lastMsgTime) / 1000;
-  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::enableSyncTreeDisplay()
 {
   ui->syncTreeButton->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 shared_ptr<const Data>& data,
-                    size_t routablePrefixOffset,
-                    bool isIntroducer)
-{
-  OnDataValidated onValidated = bind(&ChatDialog::onReplyValidated,
-                                     this, _1,
-                                     //RoutablePrefix will be removed before passing to validator
-                                     interest.getName().size()-routablePrefixOffset,
-                                     isIntroducer);
-
-  OnDataValidationFailed onFailed = bind(&ChatDialog::onReplyValidationFailed,
-                                         this, _1, _2);
-
-  if (routablePrefixOffset > 0) {
-    // It is an encapsulated packet, we only validate the inner packet.
-    shared_ptr<Data> innerData = make_shared<Data>();
-    innerData->wireDecode(data->getContent().blockFromValue());
-    m_invitationValidator->validate(*innerData, onValidated, onFailed);
-  }
-  else
-    m_invitationValidator->validate(*data, onValidated, onFailed);
-}
-
-void
-ChatDialog::onReplyTimeout(const ndn::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 ndn::shared_ptr<const ndn::Data>& data)
-{
-  Data innerData;
-  innerData.wireDecode(data->getContent().blockFromValue());
-  Sync::IntroCertificate introCert(innerData);
-  m_sock->addParticipant(introCert);
-  plotTrustTree();
-}
-
-void
-ChatDialog::onIntroCertTimeout(const ndn::Interest& interest, int retry, const QString& msg)
-{
-  // _LOG_DEBUG("onIntroCertTimeout: " << msg.toStdString());
+  ui->syncTreeViewer->show();
+  fitView();
 }
 
 } // namespace chronos
diff --git a/src/chat-dialog.hpp b/src/chat-dialog.hpp
index 7c63b30..7f1a726 100644
--- a/src/chat-dialog.hpp
+++ b/src/chat-dialog.hpp
@@ -20,30 +20,16 @@
 #include <QTimer>
 
 #ifndef Q_MOC_RUN
-#include "common.hpp"
-#include "contact-manager.hpp"
 #include "invitation.hpp"
-#include "contact.hpp"
-#include "chatbuf.pb.h"
-#include "intro-cert-list.pb.h"
+
 #include "digest-tree-scene.hpp"
 #include "trust-tree-scene.hpp"
 #include "trust-tree-node.hpp"
-#include "validator-invitation.hpp"
-#include <sync-socket.h>
-#include <sync-seq-no.h>
-#include <ndn-cxx/security/key-chain.hpp>
-#include <boost/thread/locks.hpp>
-#include <boost/thread/recursive_mutex.hpp>
-#include <boost/thread/thread.hpp>
+#include "chat-dialog-backend.hpp"
+
 #include "chatroom-info.hpp"
 #endif
 
-#include "invite-list-dialog.hpp"
-
-
-#define MAX_HISTORY_ENTRY   20
-
 namespace Ui {
 class ChatDialog;
 }
@@ -56,37 +42,17 @@
 
 public:
   explicit
-  ChatDialog(ContactManager* contactManager,
-             shared_ptr<ndn::Face> face,
-             const ndn::IdentityCertificate& myCertificate,
-             const Name& chatroomPrefix,
-             const Name& localPrefix,
+  ChatDialog(const Name& chatroomPrefix,
+             const Name& userChatPrefix,
+             const Name& routingPrefix,
+             const std::string& chatroomName,
              const std::string& nick,
-             bool witSecurity,
+             bool isSecured = false,
              QWidget* parent = 0);
 
   ~ChatDialog();
 
   void
-  addSyncAnchor(const Invitation& invitation);
-
-  void
-  processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>&, Sync::SyncSocket *);
-
-  void
-  processDataWrapper(const shared_ptr<const Data>& data);
-
-  void
-  processDataNoShowWrapper(const shared_ptr<const Data>& data);
-
-  void
-  processRemoveWrapper(const std::string& prefix);
-
-  //ymj
-  shared_ptr<ChatroomInfo>
-  getChatroomInfo() const;
-
-  void
   closeEvent(QCloseEvent* e);
 
   void
@@ -98,91 +64,29 @@
   void
   showEvent(QShowEvent* e);
 
+  ChatDialogBackend*
+  getBackend()
+  {
+    return &m_backend;
+  }
+
+  void
+  addSyncAnchor(const Invitation& invitation)
+  {
+  }
+
+  shared_ptr<ChatroomInfo>
+  getChatroomInfo();
+
 private:
   void
-  updatePrefix();
-
-  void
-  updateLabels();
-
-  void
-  initializeSync();
-
-  void
-  sendInvitation(shared_ptr<Contact> contact, bool isIntroducer);
-
-  void
-  replyWrapper(const Interest& interest, Data& data,
-               size_t routablePrefixOffset, bool isIntroducer);
-
-  void
-  replyTimeoutWrapper(const 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 Name& identity);
-
-  void
-  invitationAccepted(const ndn::IdentityCertificate& inviteeCert,
-                     const Name& inviteePrefix, bool isIntroducer);
-
-  void
-  fetchIntroCert(const Name& identity, const Name& prefix);
-
-  void
-  onIntroCertList(const Interest& interest, const Data& data);
-
-  void
-  onIntroCertListTimeout(const Interest& interest, int retry, const std::string& msg);
-
-  void
-  introCertWrapper(const Interest& interest, Data& data);
-
-  void
-  introCertTimeoutWrapper(const 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 Name& prefix, const Interest& interest);
-
-  void
-  onCertSingleRegisterFailed(const Name& prefix, const std::string& msg);
-
-
-  void
-  sendMsg(SyncDemo::ChatMessage& msg);
-
-  void
   disableSyncTreeDisplay();
 
   void
-  appendMessage(const SyncDemo::ChatMessage msg, bool isHistory = false);
+  appendChatMessage(const QString& nick, const QString& text, time_t timestamp);
 
   void
-  processRemove(QString prefix);
-
-  ndn::Name
-  getInviteeRoutablePrefix(const Name& invitee);
-
-  void
-  formChatMessage(const QString& text, SyncDemo::ChatMessage& msg);
-
-  void
-  formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type);
+  appendControlMessage(const QString& nick, const QString& action, time_t timestamp);
 
   QString
   formatTime(time_t timestamp);
@@ -190,61 +94,29 @@
   void
   printTimeInCell(QTextTable* table, time_t timestamp);
 
-  std::string
-  getRandomString();
-
   void
   showMessage(const QString&, const QString&);
 
   void
   fitView();
 
-  void
-  summonReaper();
-
-  void
-  getTree(TrustTreeNodeList& nodeList);
-
-  void
-  plotTrustTree();
-
 signals:
   void
-  processData(const ndn::shared_ptr<const ndn::Data>& data,
-              bool show, bool isHistory);
+  shutdownBackend();
 
   void
-  processTreeUpdate(const std::vector<Sync::MissingDataInfo>);
+  msgToSent(QString text, time_t timestamp);
 
   void
   closeChatDialog(const QString& chatroomName);
 
   void
-  inivationRejection(const QString& msg);
-
-  void
   showChatMessage(const QString& chatroomName, const QString& from, const QString& data);
 
   void
   resetIcon();
 
   void
-  reply(const ndn::Interest& interest, const ndn::shared_ptr<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::shared_ptr<const ndn::Data>& data);
-
-  void
-  introCertTimeout(const ndn::Interest& interest, int retry, const QString& msg);
-
-  void
-  waitForContactList();
-
-  void
   rosterChanged(const chronos::ChatroomInfo& info);
 
 public slots:
@@ -252,13 +124,31 @@
   onShow();
 
   void
-  onLocalPrefixUpdated(const QString& localPrefix);
-
-  void
-  onClose();
+  shutdown();
 
 private slots:
   void
+  updateSyncTree(std::vector<chronos::NodeInfo> updates, QString rootDigest);
+
+  void
+  receiveChatMessage(QString nick, QString text, time_t timestamp);
+
+  void
+  addSession(QString sessionPrefix, QString nick, time_t timestamp);
+
+  void
+  removeSession(QString sessionPrefix, QString nick, time_t timestamp);
+
+  void
+  updateNick(QString sessionPrefix, QString nick);
+
+  void
+  receiveMessage(QString sessionPrefix);
+
+  void
+  updateLabels(ndn::Name newChatPrefix);
+
+  void
   onReturnPressed();
 
   void
@@ -268,97 +158,21 @@
   onTrustTreeButtonPressed();
 
   void
-  onProcessData(const ndn::shared_ptr<const ndn::Data>& data, bool show, bool isHistory);
-
-  void
-  onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>&);
-
-  void
-  onReplot();
-
-  void
-  onRosterChanged(QStringList staleUserList);
-
-  void
-  onInviteListDialogRequested();
-
-  void
-  sendJoin();
-
-  void
-  sendHello();
-
-  void
-  sendLeave();
-
-  void
   enableSyncTreeDisplay();
 
-  void
-  reap();
-
-  void
-  onSendInvitation(QString invitee);
-
-  void
-  onReply(const ndn::Interest& interest, const ndn::shared_ptr<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::shared_ptr<const ndn::Data>& data);
-
-  void
-  onIntroCertTimeout(const ndn::Interest& interest, int retry, const QString& msg);
-
 private:
-  Ui::ChatDialog *ui;
-  ndn::KeyChain m_keyChain;
+  Ui::ChatDialog* ui;
 
-  ContactManager* m_contactManager;
-  shared_ptr<ndn::Face> m_face;
-
-  ndn::IdentityCertificate m_myCertificate;
-  Name m_identity;
-
-  Name m_certListPrefix;
-  const ndn::RegisteredPrefixId* m_certListPrefixId;
-  Name m_certSinglePrefix;
-  const ndn::RegisteredPrefixId* m_certSinglePrefixId;
+  ChatDialogBackend m_backend;
 
   std::string m_chatroomName;
-  Name m_chatroomPrefix;
-  Name m_localPrefix;
-  bool m_useRoutablePrefix;
-  Name m_chatPrefix;
-  Name m_localChatPrefix;
-  std::string m_nick;
-  DigestTreeScene *m_scene;
-  TrustTreeScene *m_trustScene;
-  QStringListModel *m_rosterModel;
-  QTimer* m_timer;
+  QString m_nick;
+  bool m_isSecured;
 
 
-  int64_t m_lastMsgTime;
-  int m_randomizedInterval;
-  bool m_joined;
-
-  Sync::SyncSocket *m_sock;
-  uint64_t m_session;
-  shared_ptr<ndn::SecRuleRelative> m_dataRule;
-
-  InviteListDialog* m_inviteListDialog;
-  shared_ptr<ValidatorInvitation> m_invitationValidator;
-
-  boost::recursive_mutex m_msgMutex;
-  boost::recursive_mutex m_sceneMutex;
-  QList<QString> m_zombieList;
-  int m_zombieIndex;
-
-  //ymj
-  ChatroomInfo::TrustModel m_trustModel;
+  DigestTreeScene* m_scene;
+  TrustTreeScene* m_trustScene;
+  QStringListModel* m_rosterModel;
 };
 
 } // namespace chronos
diff --git a/src/controller.cpp b/src/controller.cpp
index d99b7a6..b52c188 100644
--- a/src/controller.cpp
+++ b/src/controller.cpp
@@ -19,6 +19,7 @@
 #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"
@@ -547,9 +548,9 @@
   connect(chatDialog, SIGNAL(rosterChanged(const chronos::ChatroomInfo&)),
           this, SLOT(onRosterChanged(const chronos::ChatroomInfo&)));
   connect(this, SIGNAL(localPrefixUpdated(const QString&)),
-          chatDialog, SLOT(onLocalPrefixUpdated(const QString&)));
+          chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
   connect(this, SIGNAL(localPrefixConfigured(const QString&)),
-          chatDialog, SLOT(onLocalPrefixUpdated(const QString&)));
+          chatDialog->getBackend(), SLOT(updateRoutingPrefix(const QString&)));
 
   QAction* chatAction = new QAction(chatroomName, this);
   m_chatActionList[chatroomName.toStdString()] = chatAction;
@@ -558,7 +559,8 @@
 
   QAction* closeAction = new QAction(chatroomName, this);
   m_closeActionList[chatroomName.toStdString()] = closeAction;
-  connect(closeAction, SIGNAL(triggered()), chatDialog, SLOT(onClose()));
+  connect(closeAction, SIGNAL(triggered()),
+          chatDialog, SLOT(shutdown()));
 
   updateMenu();
 }
@@ -734,7 +736,7 @@
 {
   while (!m_chatDialogList.empty()) {
     ChatDialogList::const_iterator it = m_chatDialogList.begin();
-    onRemoveChatDialog(QString::fromStdString(it->first));
+    it->second->shutdown();
   }
 
   if (m_invitationListenerId != 0)
@@ -775,9 +777,16 @@
   // 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());
+
   ChatDialog* chatDialog
-    = new ChatDialog(&m_contactManager, m_face, *idCert, chatroomPrefix
-                     , m_localPrefix, m_nick, secured);
+    = new ChatDialog(chatroomPrefix,
+                     chatPrefix,
+                     m_localPrefix,
+                     chatroomName.toStdString(),
+                     m_nick);
 
   addChatDialog(chatroomName, chatDialog);
   chatDialog->show();
@@ -845,9 +854,18 @@
     //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(&m_contactManager, m_face, *idCert,
-                       chatroomPrefix, m_localPrefix, m_nick, true);
+      = new ChatDialog(chatroomPrefix,
+                       chatPrefix,
+                       m_localPrefix,
+                       invitation.getChatroom(),
+                       m_nick,
+                       true);
+
     chatDialog->addSyncAnchor(invitation);
 
     addChatDialog(QString::fromStdString(invitation.getChatroom()), chatDialog);
diff --git a/src/digest-tree-scene.cpp b/src/digest-tree-scene.cpp
index 07e5dea..e7adba9 100644
--- a/src/digest-tree-scene.cpp
+++ b/src/digest-tree-scene.cpp
@@ -24,55 +24,52 @@
 namespace chronos {
 
 static const double Pi = 3.14159265358979323846264338327950288419717;
+static const int NODE_SIZE = 40;
 
 //DisplayUserPtr DisplayUserNullPtr;
 
 DigestTreeScene::DigestTreeScene(QWidget *parent)
   : QGraphicsScene(parent)
 {
-  previouslyUpdatedUser = DisplayUserNullPtr;
+  m_previouslyUpdatedUser = DisplayUserNullPtr;
 }
 
 void
-DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
+DigestTreeScene::processSyncUpdate(const std::vector<chronos::NodeInfo>& nodeInfos,
+                                   const QString& digest)
 {
-  int n = v.size();
-  bool rePlot = false;
-  for (int i = 0; i < n; i++) {
-    QString routablePrefix(v[i].prefix.c_str());
-    QString prefix = trimRoutablePrefix(routablePrefix);
+  m_rootDigest = digest;
 
-    Roster_iterator it = m_roster.find(prefix);
+  bool rePlot = false;
+
+  // Update roster info
+  for (int i = 0; i < nodeInfos.size(); i++) {
+    Roster_iterator it = m_roster.find(nodeInfos[i].sessionPrefix);
     if (it == m_roster.end()) {
-      // std::cout << "processUpdate v[" << i << "]: " << prefix.toStdString() << std::endl;
       rePlot = true;
+
       DisplayUserPtr p(new DisplayUser());
-      time_t tempTime = ::time(0) + 1;
-      p->setReceived(tempTime);
-      p->setPrefix(prefix);
-      p->setSeq(v[i].high);
+      p->setPrefix(nodeInfos[i].sessionPrefix);
+      p->setSeq(nodeInfos[i].seqNo);
       m_roster.insert(p->getPrefix(), p);
     }
     else {
-      it.value()->setSeq(v[i].high);
+      it.value()->setSeq(nodeInfos[i].seqNo);
     }
   }
 
-  if (rePlot) {
-    plot(digest);
-    QTimer::singleShot(2100, this, SLOT(emitReplot()));
-  }
+  if (rePlot)
+    // If new nodes exist, we need to re-arrange node
+    plot(m_rootDigest);
   else {
-    for (int i = 0; i < n; i++) {
-      QString routablePrefix(v[i].prefix.c_str());
-      QString prefix = trimRoutablePrefix(routablePrefix);
-
-      Roster_iterator it = m_roster.find(prefix);
+    // No new node, update seqNo & digest
+    for (int i = 0; i < nodeInfos.size(); i++) {
+      Roster_iterator it = m_roster.find(nodeInfos[i].sessionPrefix);
       if (it != m_roster.end()) {
         DisplayUserPtr p = it.value();
         QGraphicsTextItem *item = p->getSeqTextItem();
         QGraphicsRectItem *rectItem = p->getInnerRectItem();
-        std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+        std::string s = boost::lexical_cast<std::string>(p->getSeqNo());
         item->setPlainText(s.c_str());
         QRectF textBR = item->boundingRect();
         QRectF rectBR = rectItem->boundingRect();
@@ -80,14 +77,57 @@
                      rectBR.y() + (rectBR.height() - textBR.height())/2);
       }
     }
-    m_rootDigest->setPlainText(digest);
+    m_displayRootDigest->setPlainText(digest);
   }
 }
 
 void
-DigestTreeScene::emitReplot()
+DigestTreeScene::updateNick(QString sessionPrefix, QString nick)
 {
-  emit replot();
+  Roster_iterator it = m_roster.find(sessionPrefix);
+  if (it != m_roster.end()) {
+    DisplayUserPtr p = it.value();
+    if (nick != p->getNick()) {
+      p->setNick(nick);
+      QGraphicsTextItem *nickItem = p->getNickTextItem();
+      QGraphicsRectItem *nickRectItem = p->getNickRectItem();
+      nickItem->setPlainText(p->getNick());
+      QRectF rectBR = nickRectItem->boundingRect();
+      QRectF nickBR = nickItem->boundingRect();
+      nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
+    }
+  }
+}
+
+void
+DigestTreeScene::messageReceived(QString sessionPrefix)
+{
+  Roster_iterator it = m_roster.find(sessionPrefix);
+  if (it != m_roster.end()) {
+    DisplayUserPtr p = it.value();
+
+    reDrawNode(p, Qt::red);
+
+    if (m_previouslyUpdatedUser != DisplayUserNullPtr && m_previouslyUpdatedUser != p) {
+      reDrawNode(m_previouslyUpdatedUser, Qt::darkBlue);
+    }
+
+    m_previouslyUpdatedUser = p;
+  }
+}
+
+void
+DigestTreeScene::clearAll()
+{
+  clear();
+  m_roster.clear();
+}
+
+void
+DigestTreeScene::removeNode(const QString sessionPrefix)
+{
+  m_roster.remove(sessionPrefix);
+  plot(m_rootDigest);
 }
 
 QStringList
@@ -105,117 +145,36 @@
   return rosterList;
 }
 
-void
-DigestTreeScene::msgReceived(QString routablePrefix, QString nick)
+QStringList
+DigestTreeScene::getRosterPrefixList()
 {
-  QString prefix = trimRoutablePrefix(routablePrefix);
-  Roster_iterator it = m_roster.find(prefix);
-  // std::cout << "msgReceived prefix: " << prefix.toStdString() << std::endl;
-  if (it != m_roster.end()) {
-    // std::cout << "Updating for prefix = " << prefix.toStdString() <<
-    // " nick = " << nick.toStdString() << std::endl;
-    DisplayUserPtr p = it.value();
-    p->setReceived(::time(0) + 1);
-    if (nick != p->getNick()) {
-      // std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
-      p->setNick(nick);
-      QGraphicsTextItem *nickItem = p->getNickTextItem();
-      QGraphicsRectItem *nickRectItem = p->getNickRectItem();
-      nickItem->setPlainText(p->getNick());
-      QRectF rectBR = nickRectItem->boundingRect();
-      QRectF nickBR = nickItem->boundingRect();
-      nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
-      emit rosterChanged(QStringList());
-    }
-
-    reDrawNode(p, Qt::red);
-
-    if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p) {
-      reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
-    }
-
-    previouslyUpdatedUser = p;
-  }
-}
-
-void
-DigestTreeScene::clearAll()
-{
-  clear();
-  m_roster.clear();
-}
-
-bool
-DigestTreeScene::removeNode(const QString prefix)
-{
-  int removedCount = m_roster.remove(prefix);
-  return (removedCount > 0);
-}
-
-void
-DigestTreeScene::plot(QString digest)
-{
-#ifdef _DEBUG
-  std::cout << "Plotting at time: " << ::time(NULL) << std::endl;
-#endif
-  clear();
-
-  int nodeSize = 40;
-
-  int siblingDistance = 100, levelDistance = 100;
-  std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
-  layout->setSiblingDistance(siblingDistance);
-  layout->setLevelDistance(levelDistance);
-
-  // do some cleaning, get rid of stale member info
-  Roster_iterator it = m_roster.begin();
-  QStringList staleUserList;
-  while (it != m_roster.end()) {
+  QStringList prefixList;
+  RosterIterator it(m_roster);
+  while (it.hasNext()) {
+    it.next();
     DisplayUserPtr p = it.value();
     if (p != DisplayUserNullPtr) {
-      time_t now = ::time(NULL);
-      if (now - p->getReceived() >= FRESHNESS) {
-#ifdef _DEBUG
-        std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
-        std::cout << "now - last = " << now - p->getReceived() << std::endl;
-#endif
-        staleUserList << p->getNick();
-        p = DisplayUserNullPtr;
-        it = m_roster.erase(it);
-      }
-      else {
-        if (!m_currentPrefix.startsWith("/private/local") &&
-            p->getPrefix().startsWith("/private/local")) {
-#ifdef _DEBUG
-          std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
-#endif
-          staleUserList << p->getNick();
-          p = DisplayUserNullPtr;
-          it = m_roster.erase(it);
-          continue;
-        }
-        ++it;
-      }
-    }
-    else {
-      it = m_roster.erase(it);
+      prefixList << "- " + p->getPrefix();
     }
   }
+  return prefixList;
+}
 
-  // for simpicity here, whenever we replot, we also redo the roster list
-  emit rosterChanged(staleUserList);
+void
+DigestTreeScene::plot(QString rootDigest)
+{
+  clear();
 
-  int n = m_roster.size();
+  shared_ptr<TreeLayout> layout(new OneLevelTreeLayout());
+  layout->setSiblingDistance(100);
+  layout->setLevelDistance(100);
 
-  std::vector<TreeLayout::Coordinate> childNodesCo(n);
-
+  std::vector<TreeLayout::Coordinate> childNodesCo(m_roster.size());
   layout->setOneLevelLayout(childNodesCo);
+  plotEdge(childNodesCo, NODE_SIZE);
+  plotNode(childNodesCo, rootDigest, NODE_SIZE);
 
-  plotEdge(childNodesCo, nodeSize);
-  plotNode(childNodesCo, digest, nodeSize);
-
-  previouslyUpdatedUser = DisplayUserNullPtr;
-
+  m_previouslyUpdatedUser = DisplayUserNullPtr;
 }
 
 void
@@ -266,7 +225,7 @@
   digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
   digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2,
                      - nodeSize + 5);
-  m_rootDigest = digestItem;
+  m_displayRootDigest = digestItem;
 
   // plot child nodes
   for (int i = 0; i < n; i++) {
@@ -288,7 +247,7 @@
                                                QBrush(Qt::lightGray));
     p->setInnerRectItem(innerRectItem);
 
-    std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+    std::string s = boost::lexical_cast<std::string>(p->getSeqNo());
     QGraphicsTextItem *seqItem = addText(s.c_str());
     seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
     QRectF seqBoundingRect = seqItem->boundingRect();
@@ -317,7 +276,7 @@
     QGraphicsRectItem *innerItem = p->getInnerRectItem();
     innerItem->setBrush(QBrush(Qt::lightGray));
     QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
-    std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+    std::string s = boost::lexical_cast<std::string>(p->getSeqNo());
     seqTextItem->setPlainText(s.c_str());
     QRectF textBR = seqTextItem->boundingRect();
     QRectF innerBR = innerItem->boundingRect();
@@ -325,26 +284,6 @@
                         innerBR.y() + (innerBR.height() - textBR.height())/2);
 }
 
-QString
-DigestTreeScene::trimRoutablePrefix(QString prefix)
-{
-  bool encaped = false;
-  ndn::Name prefixName(prefix.toStdString());
-
-  size_t offset = 0;
-  for (ndn::Name::const_iterator it  = prefixName.begin(); it != prefixName.end(); it++, offset++) {
-    if (it->toUri() == "%F0.") {
-      encaped = true;
-      break;
-    }
-  }
-
-  if (!encaped)
-    return prefix;
-  else
-    return QString(prefixName.getSubName(offset+1).toUri().c_str());
-}
-
 } // namespace chronos
 
 #if WAF
diff --git a/src/digest-tree-scene.hpp b/src/digest-tree-scene.hpp
index 138f7f4..51847dc 100644
--- a/src/digest-tree-scene.hpp
+++ b/src/digest-tree-scene.hpp
@@ -18,8 +18,8 @@
 
 #ifndef Q_MOC_RUN
 #include "tree-layout.hpp"
-#include <sync-seq-no.h>
-#include <sync-logic.h>
+#include "chat-dialog-backend.hpp"
+#include <Leaf.hpp>
 #include <ctime>
 #include <vector>
 #include <boost/shared_ptr.hpp>
@@ -49,44 +49,29 @@
   DigestTreeScene(QWidget *parent = 0);
 
   void
-  processUpdate(const std::vector<Sync::MissingDataInfo>& v, QString digest);
+  processSyncUpdate(const std::vector<chronos::NodeInfo>& nodeInfos,
+                    const QString& digest);
 
   void
-  msgReceived(QString prefix, QString nick);
+  updateNick(QString sessionPrefix, QString nick);
+
+  void
+  messageReceived(QString sessionPrefix);
 
   void
   clearAll();
 
-  bool
-  removeNode(const QString prefix);
-
   void
-  plot(QString digest);
+  removeNode(const QString sessionPrefix);
 
   QStringList
   getRosterList();
 
-  void
-  setCurrentPrefix(QString prefix)
-  {
-    m_currentPrefix = prefix;
-  }
-
-  QMap<QString, DisplayUserPtr> getRosterFull()
-  {
-    return m_roster;
-  }
-
-signals:
-  void
-  replot();
+  QStringList
+  getRosterPrefixList();
 
   void
-  rosterChanged(QStringList);
-
-private slots:
-  void
-  emitReplot();
+  plot(QString rootDigest);
 
 private:
   void
@@ -98,29 +83,25 @@
   void
   reDrawNode(DisplayUserPtr p, QColor rimColor);
 
-  QString
-  trimRoutablePrefix(QString prefix);
-
 private:
   Roster m_roster;
-  QGraphicsTextItem* m_rootDigest;
-  DisplayUserPtr previouslyUpdatedUser;
-  QString m_currentPrefix;
+
+  QString m_rootDigest;
+  QGraphicsTextItem* m_displayRootDigest;
+
+  DisplayUserPtr m_previouslyUpdatedUser;
 };
 
 class User
 {
 public:
   User()
-    :m_received(::time(NULL))
   {
   }
 
-  User(QString n, QString p, QString c)
+  User(QString n, QString p)
     : m_nick(n)
     , m_prefix(p)
-    , m_chatroom(c)
-    , m_received(::time(NULL))
   {
   }
 
@@ -137,29 +118,11 @@
   }
 
   void
-  setChatroom(QString chatroom)
-  {
-    m_chatroom = chatroom;
-  }
-
-  void
-  setSeq(Sync::SeqNo seq)
+  setSeq(chronosync::SeqNo seq)
   {
     m_seq = seq;
   }
 
-  void
-  setReceived(time_t t)
-  {
-    m_received = t;
-  }
-
-  void
-  setOriginPrefix(QString originPrefix)
-  {
-    m_originPrefix = originPrefix;
-  }
-
   QString
   getNick()
   {
@@ -171,34 +134,16 @@
     return m_prefix;
   }
 
-  QString getChatroom()
-  {
-    return m_chatroom;
-  }
-
-  QString getOriginPrefix()
-  {
-    return m_originPrefix;
-  }
-
-  Sync::SeqNo
+  chronosync::SeqNo
   getSeqNo()
   {
     return m_seq;
   }
 
-  time_t getReceived()
-  {
-    return m_received;
-  }
-
 private:
   QString m_nick;
   QString m_prefix;
-  QString m_chatroom;
-  QString m_originPrefix;
-  Sync::SeqNo m_seq;
-  time_t m_received;
+  chronosync::SeqNo m_seq;
 };
 
 class DisplayUser : public User
@@ -211,8 +156,8 @@
   {
   }
 
-  DisplayUser(QString n, QString p , QString c)
-    : User(n, p, c)
+  DisplayUser(QString n, QString p)
+    : User(n, p)
     , m_seqTextItem(NULL)
     , m_nickTextItem(NULL)
     , m_rimRectItem(NULL)