Add chatroom discovery logic

Change-Id: I1b65b7bbcf321c51cb00e8d1c05a42291601a284
diff --git a/src/chat-dialog.cpp b/src/chat-dialog.cpp
index 442e866..93d7dd0 100644
--- a/src/chat-dialog.cpp
+++ b/src/chat-dialog.cpp
@@ -78,6 +78,8 @@
   , m_sock(NULL)
   , m_session(static_cast<uint64_t>(time::toUnixTimestamp(time::system_clock::now()).count()))
   , m_inviteListDialog(new InviteListDialog)
+  //ymj
+  //, m_trustModel(withSecurity)
 {
   qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
   qRegisterMetaType<ndn::shared_ptr<const ndn::Data> >("ndn.DataPtr");
@@ -155,7 +157,11 @@
             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();
 }
@@ -180,7 +186,7 @@
 void
 ChatDialog::addSyncAnchor(const Invitation& invitation)
 {
-  // _LOG_DEBUG("Add sync anchor from invation");
+  // _LOG_DEBUG("Add sync anchor from invitation");
   // Add inviter certificate as trust anchor.
   m_sock->addParticipant(invitation.getInviterCertificate());
   plotTrustTree();
@@ -228,7 +234,7 @@
                               "system tray. To close the chatroom, "
                               "choose <b>Close chatroom</b> in the "
                               "context memu of the system tray entry."));
-  hide();
+  hide();//ymj
   e->ignore();
 }
 
@@ -282,6 +288,7 @@
 
   if (m_certListPrefixId)
     m_face->unsetInterestFilter(m_certListPrefixId);
+
   m_certListPrefixId = m_face->setInterestFilter(m_certListPrefix,
                                                  bind(&ChatDialog::onCertListInterest,
                                                       this, _1, _2),
@@ -522,7 +529,7 @@
 }
 
 void
-ChatDialog::onCertListInterest(const Name& prefix, const Interest& interest)
+ChatDialog::onCertListInterest(const ndn::Name& prefix, const ndn::Interest& interest)
 {
   vector<Name> certNameList;
   m_sock->getIntroCertNames(certNameList);
@@ -545,7 +552,7 @@
 }
 
 void
-ChatDialog::onCertListRegisterFailed(const Name& prefix, const string& msg)
+ChatDialog::onCertListRegisterFailed(const ndn::Name& prefix, const std::string& msg)
 {
   // _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
 }
@@ -567,7 +574,7 @@
 }
 
 void
-ChatDialog::onCertSingleRegisterFailed(const Name& prefix, const string& msg)
+ChatDialog::onCertSingleRegisterFailed(const Name& prefix, const std::string& msg)
 {
   // _LOG_DEBUG("ChatDialog::onCertListRegisterFailed failed: " + msg);
 }
@@ -719,7 +726,7 @@
   msg.set_to(m_chatroomName);
   msg.set_data(text.toStdString());
   int32_t seconds =
-    static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000000000);
+    static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000);
   msg.set_timestamp(seconds);
   msg.set_type(SyncDemo::ChatMessage::CHAT);
 }
@@ -731,7 +738,7 @@
   msg.set_from(m_nick);
   msg.set_to(m_chatroomName);
   int32_t seconds =
-    static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000000000);
+    static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count()/1000);
   msg.set_timestamp(seconds);
   msg.set_type(type);
 }
@@ -924,6 +931,26 @@
   }
 }
 
+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)
@@ -1052,7 +1079,7 @@
 }
 
 void
-ChatDialog::onProcessData(const shared_ptr<const Data>& data, bool show, bool isHistory)
+ChatDialog::onProcessData(const ndn::shared_ptr<const ndn::Data>& data, bool show, bool isHistory)
 {
   SyncDemo::ChatMessage msg;
   bool corrupted = false;
@@ -1065,6 +1092,9 @@
     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
@@ -1153,6 +1183,8 @@
     appendMessage(msg);
   }
   plotTrustTree();
+
+  emit rosterChanged(*getChatroomInfo());
 }
 
 void
@@ -1180,7 +1212,7 @@
 ChatDialog::sendHello()
 {
   int64_t now = time::toUnixTimestamp(time::system_clock::now()).count();
-  int elapsed = (now - m_lastMsgTime) / 1000000000;
+  int elapsed = (now - m_lastMsgTime) / 1000;
   if (elapsed >= m_randomizedInterval / 1000) {
     SyncDemo::ChatMessage msg;
     formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
@@ -1262,7 +1294,7 @@
 }
 
 void
-ChatDialog::onReplyTimeout(const Interest& interest,
+ChatDialog::onReplyTimeout(const ndn::Interest& interest,
                            size_t routablePrefixOffset)
 {
   Name interestName;
@@ -1279,7 +1311,7 @@
 }
 
 void
-ChatDialog::onIntroCert(const Interest& interest, const shared_ptr<const Data>& data)
+ChatDialog::onIntroCert(const ndn::Interest& interest, const ndn::shared_ptr<const ndn::Data>& data)
 {
   Data innerData;
   innerData.wireDecode(data->getContent().blockFromValue());
@@ -1289,13 +1321,14 @@
 }
 
 void
-ChatDialog::onIntroCertTimeout(const Interest& interest, int retry, const QString& msg)
+ChatDialog::onIntroCertTimeout(const ndn::Interest& interest, int retry, const QString& msg)
 {
   // _LOG_DEBUG("onIntroCertTimeout: " << msg.toStdString());
 }
 
 } // namespace chronos
 
+
 #if WAF
 #include "chat-dialog.moc"
 // #include "chat-dialog.cpp.moc"
diff --git a/src/chat-dialog.hpp b/src/chat-dialog.hpp
index 12051f1..9c4008e 100644
--- a/src/chat-dialog.hpp
+++ b/src/chat-dialog.hpp
@@ -9,8 +9,8 @@
  *         Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef CHRONOS_CHAT_DIALOG_HPP
-#define CHRONOS_CHAT_DIALOG_HPP
+#ifndef CHRONOCHAT_CHAT_DIALOG_HPP
+#define CHRONOCHAT_CHAT_DIALOG_HPP
 
 #include <QDialog>
 #include <QTextTable>
@@ -36,6 +36,7 @@
 #include <boost/thread/locks.hpp>
 #include <boost/thread/recursive_mutex.hpp>
 #include <boost/thread/thread.hpp>
+#include "chatroom-info.hpp"
 #endif
 
 #include "invite-list-dialog.hpp"
@@ -81,7 +82,10 @@
   void
   processRemoveWrapper(const std::string& prefix);
 
-protected:
+  //ymj
+  shared_ptr<ChatroomInfo>
+  getChatroomInfo() const;
+
   void
   closeEvent(QCloseEvent* e);
 
@@ -116,12 +120,12 @@
                       size_t routablePrefixOffset);
 
   void
-  onReplyValidated(const shared_ptr<const Data>& data,
+  onReplyValidated(const ndn::shared_ptr<const ndn::Data>& data,
                    size_t inviteeRoutablePrefixOffset,
                    bool isIntroduce);
 
   void
-  onReplyValidationFailed(const shared_ptr<const Data>& data,
+  onReplyValidationFailed(const ndn::shared_ptr<const ndn::Data>& data,
                           const std::string& failureInfo);
 
   void
@@ -147,10 +151,10 @@
   introCertTimeoutWrapper(const Interest& interest, int retry, const QString& msg);
 
   void
-  onCertListInterest(const Name& prefix, const Interest& interest);
+  onCertListInterest(const ndn::Name& prefix, const ndn::Interest& interest);
 
   void
-  onCertListRegisterFailed(const Name& prefix, const std::string& msg);
+  onCertListRegisterFailed(const ndn::Name& prefix, const std::string& msg);
 
   void
   onCertSingleInterest(const Name& prefix, const Interest& interest);
@@ -206,7 +210,8 @@
 
 signals:
   void
-  processData(const shared_ptr<const Data>& data, bool show, bool isHistory);
+  processData(const ndn::shared_ptr<const ndn::Data>& data,
+              bool show, bool isHistory);
 
   void
   processTreeUpdate(const std::vector<Sync::MissingDataInfo>);
@@ -224,21 +229,24 @@
   resetIcon();
 
   void
-  reply(const Interest& interest, const shared_ptr<const Data>& data,
+  reply(const ndn::Interest& interest, const ndn::shared_ptr<const ndn::Data>& data,
         size_t routablePrefixOffset, bool isIntroducer);
 
   void
-  replyTimeout(const Interest& interest, size_t routablePrefixOffset);
+  replyTimeout(const ndn::Interest& interest, size_t routablePrefixOffset);
 
   void
-  introCert(const Interest& interest, const shared_ptr<const Data>& data);
+  introCert(const ndn::Interest& interest, const ndn::shared_ptr<const ndn::Data>& data);
 
   void
-  introCertTimeout(const Interest& interest, int retry, const QString& msg);
+  introCertTimeout(const ndn::Interest& interest, int retry, const QString& msg);
 
   void
   waitForContactList();
 
+  void
+  rosterChanged(const chronos::ChatroomInfo& info);
+
 public slots:
   void
   onLocalPrefixUpdated(const QString& localPrefix);
@@ -257,7 +265,7 @@
   onTrustTreeButtonPressed();
 
   void
-  onProcessData(const shared_ptr<const Data>& data, bool show, bool isHistory);
+  onProcessData(const ndn::shared_ptr<const ndn::Data>& data, bool show, bool isHistory);
 
   void
   onProcessTreeUpdate(const std::vector<Sync::MissingDataInfo>&);
@@ -290,17 +298,17 @@
   onSendInvitation(QString invitee);
 
   void
-  onReply(const Interest& interest, const shared_ptr<const Data>& data,
+  onReply(const ndn::Interest& interest, const ndn::shared_ptr<const ndn::Data>& data,
           size_t routablePrefixOffset, bool isIntroducer);
 
   void
-  onReplyTimeout(const Interest& interest, size_t routablePrefixOffset);
+  onReplyTimeout(const ndn::Interest& interest, size_t routablePrefixOffset);
 
   void
-  onIntroCert(const Interest& interest, const shared_ptr<const Data>& data);
+  onIntroCert(const ndn::Interest& interest, const ndn::shared_ptr<const ndn::Data>& data);
 
   void
-  onIntroCertTimeout(const Interest& interest, int retry, const QString& msg);
+  onIntroCertTimeout(const ndn::Interest& interest, int retry, const QString& msg);
 
 private:
   Ui::ChatDialog *ui;
@@ -345,8 +353,11 @@
   boost::recursive_mutex m_sceneMutex;
   QList<QString> m_zombieList;
   int m_zombieIndex;
+
+  //ymj
+  ChatroomInfo::TrustModel m_trustModel;
 };
 
 } // namespace chronos
 
-#endif // CHRONOS_CHAT_DIALOG_HPP
+#endif // CHRONOCHAT_CHAT_DIALOG_HPP
diff --git a/src/chatroom-discovery-logic.cpp b/src/chatroom-discovery-logic.cpp
new file mode 100644
index 0000000..048d121
--- /dev/null
+++ b/src/chatroom-discovery-logic.cpp
@@ -0,0 +1,221 @@
+/* -*- 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: Mengjin Yan <jane.yan0129@gmail.com>
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "chatroom-discovery-logic.hpp"
+
+
+namespace chronos {
+
+const size_t ChatroomDiscoveryLogic::OFFSET_CHATROOM_NAME = 4;
+const size_t ChatroomDiscoveryLogic::DISCOVERY_INTEREST_NAME_SIZE = 4;
+const size_t ChatroomDiscoveryLogic::REFRESHING_INTEREST_NAME_SIZE = 5;
+const time::milliseconds ChatroomDiscoveryLogic::DEFAULT_REFRESHING_TIMER(10000);
+const Name ChatroomDiscoveryLogic::DISCOVERY_PREFIX("/ndn/broadcast/chronochat/chatroom-list");
+const time::seconds ChatroomDiscoveryLogic::m_discoveryInterval(600);
+
+ChatroomDiscoveryLogic::ChatroomDiscoveryLogic(shared_ptr<ndn::Face> face,
+                                               const UpdateCallback& updateCallback)
+  : m_face(face)
+  , m_scheduler(face->getIoService())
+  , m_onUpdate(updateCallback)
+{
+
+  m_face->setInterestFilter(DISCOVERY_PREFIX,
+                            bind(&ChatroomDiscoveryLogic::onDiscoveryInterest,
+                                 this, _1, _2),
+                            bind(&ChatroomDiscoveryLogic::onPrefixRegistrationFailed,
+                                 this, _1));
+}
+
+void
+ChatroomDiscoveryLogic::addLocalChatroom(const ChatroomInfo& chatroom)
+{
+  m_localChatrooms[chatroom.getName()] = chatroom;
+  m_chatrooms[chatroom.getName()] = chatroom; // no need to discover local chatroom
+}
+
+void
+ChatroomDiscoveryLogic::removeLocalChatroom(const Name::Component& chatroomName)
+{
+  m_localChatrooms.erase(chatroomName);
+  m_chatrooms.erase(chatroomName);
+}
+
+void
+ChatroomDiscoveryLogic::sendDiscoveryInterest()
+{
+  Interest discovery(DISCOVERY_PREFIX);
+  discovery.setMustBeFresh(true);
+  discovery.setInterestLifetime(time::milliseconds(10000));
+
+  Exclude exclude;
+  Chatrooms::iterator it;
+  for (it = m_chatrooms.begin(); it != m_chatrooms.end(); ++it) {
+    exclude.excludeOne(it->first);
+  }
+  discovery.setExclude(exclude);
+
+  m_face->expressInterest(discovery,
+                          bind(&ChatroomDiscoveryLogic::onReceiveData, this,
+                               _1, _2, false),
+                          bind(&ChatroomDiscoveryLogic::onDiscoveryInterestTimeout, this,
+                               _1));
+
+}
+
+void
+ChatroomDiscoveryLogic::onDiscoveryInterest(const Name& name, const Interest& interest)
+{
+  if (m_localChatrooms.empty())
+    return;
+
+  if (interest.getName() == DISCOVERY_PREFIX) {
+    // discovery
+    for (Chatrooms::const_iterator it = m_localChatrooms.begin();
+         it != m_localChatrooms.end(); ++it) {
+
+      if (!interest.getExclude().empty() &&
+          interest.getExclude().isExcluded(it->first))
+        continue;
+
+
+      Name dataName(interest.getName());
+      dataName.append(it->first);
+
+      shared_ptr<Data> chatroomInfo = make_shared<Data>(dataName);
+      chatroomInfo->setFreshnessPeriod(time::seconds(10));
+      chatroomInfo->setContent(it->second.wireEncode());
+
+      m_keyChain.sign(*chatroomInfo);
+      m_face->put(*chatroomInfo);
+      break;
+    }
+    return;
+  }
+
+  if (DISCOVERY_PREFIX.isPrefixOf(interest.getName()) &&
+      interest.getName().size() == REFRESHING_INTEREST_NAME_SIZE) {
+    // refreshing
+    Chatrooms::const_iterator it =
+      m_localChatrooms.find(interest.getName().get(OFFSET_CHATROOM_NAME));
+
+    if (it == m_localChatrooms.end())
+      return;
+
+    shared_ptr<Data> chatroomInfo = make_shared<Data>(interest.getName());
+    chatroomInfo->setFreshnessPeriod(time::seconds(10));
+    chatroomInfo->setContent(it->second.wireEncode());
+
+    m_keyChain.sign(*chatroomInfo);
+    m_face->put(*chatroomInfo);
+
+    return;
+  }
+}
+
+void
+ChatroomDiscoveryLogic::onPrefixRegistrationFailed(const Name& name)
+{
+}
+
+void
+ChatroomDiscoveryLogic::refreshChatroom(const Name::Component& chatroomName)
+{
+  Name name = DISCOVERY_PREFIX;
+  name.append(chatroomName);
+
+  BOOST_ASSERT(name.size() == REFRESHING_INTEREST_NAME_SIZE);
+
+  Interest discovery(name);
+  discovery.setMustBeFresh(true);
+  discovery.setInterestLifetime(time::milliseconds(10000));
+
+  m_face->expressInterest(discovery,
+                          bind(&ChatroomDiscoveryLogic::onReceiveData, this,
+                               _1, _2, true),
+                          bind(&ChatroomDiscoveryLogic::onRefreshingInterestTimeout, this,
+                               _1));
+
+}
+
+void
+ChatroomDiscoveryLogic::onReceiveData(const ndn::Interest& interest,
+                                      const ndn::Data& data,
+                                      const bool isRefreshing)
+{
+  Name::Component chatroomName = data.getName().get(OFFSET_CHATROOM_NAME);
+
+  ChatroomInfo chatroom;
+  chatroom.wireDecode(data.getContent().blockFromValue());
+  chatroom.setName(chatroomName);
+
+  // Tmp Disabled
+  // if (chatroom.getTrustModel() == ChatroomInfo::TRUST_MODEL_WEBOFTRUST)
+  //   addContacts(chatroom);
+
+
+  m_chatrooms[chatroomName] = chatroom;
+  m_onUpdate(chatroom, true); //add
+
+  time::milliseconds refreshingTime;
+  if (data.getFreshnessPeriod() > DEFAULT_REFRESHING_TIMER)
+    refreshingTime = data.getFreshnessPeriod();
+  else
+    refreshingTime = DEFAULT_REFRESHING_TIMER;
+
+  m_scheduler.scheduleEvent(refreshingTime,
+                            bind(&ChatroomDiscoveryLogic::refreshChatroom, this, chatroomName));
+
+  if (!isRefreshing)
+    sendDiscoveryInterest();
+}
+
+void
+ChatroomDiscoveryLogic::onRefreshingInterestTimeout(const ndn::Interest& interest)
+{
+  Name::Component chatroomName = interest.getName().get(OFFSET_CHATROOM_NAME);
+
+  Chatrooms::iterator it = m_chatrooms.find(chatroomName);
+  if (it != m_chatrooms.end()) {
+    m_onUpdate(it->second, false); //delete
+    m_chatrooms.erase(it);
+  }
+}
+
+
+void
+ChatroomDiscoveryLogic::onDiscoveryInterestTimeout(const Interest& interest)
+{
+  m_scheduler.scheduleEvent(m_discoveryInterval,
+                            bind(&ChatroomDiscoveryLogic::sendDiscoveryInterest, this));
+}
+
+void
+ChatroomDiscoveryLogic::addContacts(ChatroomInfo& chatroom)
+{
+  // Tmp Disabled
+
+  // std::vector<Name>::const_iterator nameIt;
+  // std::vector<shared_ptr<Contact> >::iterator contactIt;
+  // ContactList contactList;
+  // m_contactManager->getContactList(contactList);
+
+  // for (contactIt = contactList.begin();
+  //      contactIt != contactList.end(); ++contactIt) {
+  //   nameIt = std::find(chatroom.getParticipants().begin(),
+  //                 chatroom.getParticipants().end(), (*contactIt)->getNameSpace());
+  //   if (nameIt != chatroom.getParticipants().end())
+  //     chatroom.addContact(*nameIt);
+  // }
+}
+
+
+} //namespace chronos
diff --git a/src/chatroom-discovery-logic.hpp b/src/chatroom-discovery-logic.hpp
new file mode 100644
index 0000000..32b9c89
--- /dev/null
+++ b/src/chatroom-discovery-logic.hpp
@@ -0,0 +1,118 @@
+/* -*- 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: Mengjin Yan <jane.yan0129@gmail.com>
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHRONOCHAT_CHATROOM_DISCOVERY_LOGIC_HPP
+#define CHRONOCHAT_CHATROOM_DISCOVERY_LOGIC_HPP
+
+#include "chatroom-info.hpp"
+#include <ndn-cxx/util/scheduler.hpp>
+
+namespace chronos {
+
+class ChatroomDiscoveryLogic : noncopyable
+{
+public:
+  typedef function<void(const ChatroomInfo& chatroomName, bool isAdd)> UpdateCallback;
+
+  typedef std::map<Name::Component, chronos::ChatroomInfo> Chatrooms;
+  static const size_t OFFSET_CHATROOM_NAME;
+  static const size_t DISCOVERY_INTEREST_NAME_SIZE;
+  static const size_t REFRESHING_INTEREST_NAME_SIZE;
+  static const time::milliseconds DEFAULT_REFRESHING_TIMER;
+  static const Name DISCOVERY_PREFIX;
+
+public:
+  explicit
+  ChatroomDiscoveryLogic(shared_ptr<ndn::Face> face,
+                         const UpdateCallback& updateCallback);
+
+
+  /** \brief obtain the ongoing chatroom list
+   */
+  const Chatrooms&
+  getChatrooms() const;
+
+  /** \brief add a local chatroom in the ongoing chatroom list
+   */
+  void
+  addLocalChatroom(const ChatroomInfo& chatroom);
+
+  void
+  removeLocalChatroom(const Name::Component& chatroomName);
+
+  /** \brief send discovery interest
+   */
+  void
+  sendDiscoveryInterest();
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+  /**
+   */
+  void
+  onDiscoveryInterest(const Name& name, const Interest& interest);
+
+  /**
+   */
+  void
+  onPrefixRegistrationFailed(const Name& name);
+
+  /** \brief schedule another discovery
+   */
+  void
+  onDiscoveryInterestTimeout(const Interest& interest);
+
+  /** \brief send interest to find if the certain chatroom exists
+   */
+  void
+  refreshChatroom(const Name::Component& chatroomName);
+
+  /** \brief copy the contact from the participants of the chatroom to contacts of the chatroom
+   */
+  void
+  addContacts(ChatroomInfo& chatroom);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+
+  /** \brief erase the chatroom from the ongoing chatroom list
+   */
+  void
+  onRefreshingInterestTimeout(const Interest& interest);
+
+  /** \brief operate the chatroom data and schedule discovery and refreshing process
+   */
+  void
+  onReceiveData(const ndn::Interest& interest, const ndn::Data& data, const bool isRefreshing);
+
+private:
+  static const time::seconds m_discoveryInterval;
+
+  shared_ptr<ndn::Face> m_face;
+
+  ndn::KeyChain m_keyChain;
+
+  Chatrooms m_chatrooms;
+  Chatrooms m_localChatrooms;
+
+  ndn::Scheduler m_scheduler;
+
+  UpdateCallback m_onUpdate;
+
+};
+
+inline const ChatroomDiscoveryLogic::Chatrooms&
+ChatroomDiscoveryLogic::getChatrooms() const
+{
+  return m_chatrooms;
+}
+
+} // namespace chronos
+
+#endif // CHRONOCHAT_CHATROOM_DISCOVERY_LOGIC_HPP
diff --git a/src/chatroom-info.cpp b/src/chatroom-info.cpp
new file mode 100644
index 0000000..2b23719
--- /dev/null
+++ b/src/chatroom-info.cpp
@@ -0,0 +1,136 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Mengjin Yan <jane.yan0129@gmail.com>
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+#include "chatroom-info.hpp"
+
+namespace chronos {
+
+ChatroomInfo::ChatroomInfo()
+{
+}
+
+ChatroomInfo::ChatroomInfo(const Block& chatroomWire)
+{
+  this->wireDecode(chatroomWire);
+}
+
+template<bool T>
+size_t
+ChatroomInfo::wireEncode(ndn::EncodingImpl<T>& block) const
+{
+  size_t totalLength = 0;
+
+  //Chatroom := CHATROOM-TYPE TLV-LENGTH
+  //              TrustModel
+  //              Participant+
+
+  //Participants
+  for (std::vector<Name>::const_reverse_iterator it = m_participants.rbegin();
+       it != m_participants.rend(); ++it) {
+    size_t entryLength = 0;
+
+    entryLength += it->wireEncode(block);
+    entryLength += block.prependVarNumber(entryLength);
+    entryLength += block.prependVarNumber(tlv::PARTICIPANT);
+    totalLength += entryLength;
+  }
+
+  //TrustModel
+  totalLength += prependNonNegativeIntegerBlock(block, tlv::TRUSTMODEL, m_trustModel);
+
+  //type = TYPE_CHATROOM;
+  totalLength += block.prependVarNumber(totalLength);
+  totalLength += block.prependVarNumber(tlv::CHATROOM);
+
+  return totalLength;
+}
+
+const Block&
+ChatroomInfo::wireEncode() const
+{
+  ndn::EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  ndn::EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  m_wire.parse();
+
+  return m_wire;
+}
+
+void
+ChatroomInfo::wireDecode(const Block& chatroomWire)
+{
+  m_wire = chatroomWire;
+  m_wire.parse();
+
+  m_participants.clear();
+
+  //Chatroom := CHATROOM-TYPE TLV-LENGTH
+  //              TrustModel
+  //              Participant+
+
+  if (m_wire.type() != tlv::CHATROOM)
+    throw Error("Unexpected TLV number when decoding chatroom packet");
+
+  Block::element_const_iterator i = m_wire.elements_begin();
+
+  //TrustModel
+  if (i == m_wire.elements_end() || i->type() != tlv::TRUSTMODEL)
+    throw Error("Missing TrustModel");
+  m_trustModel =
+      static_cast<TrustModel>(readNonNegativeInteger(*i));
+
+  ++i;
+
+  //Participants
+  for (; i != m_wire.elements_end() && i->type() == tlv::PARTICIPANT; ++i) {
+    Name name;
+    name.wireDecode(i->blockFromValue());
+    m_participants.push_back(name);
+  }
+  if (m_participants.empty())
+    throw Error("Missing Participant");
+  if (i != m_wire.elements_end()) {
+    throw Error("Unexpected element");
+  }
+}
+
+void
+ChatroomInfo::addParticipant(const Name& participant)
+{
+  m_wire.reset();
+  m_participants.push_back(participant);
+}
+
+void
+ChatroomInfo::addContact(const Name& contact)
+{
+  m_wire.reset();
+  m_contacts.push_back(contact);
+}
+
+void
+ChatroomInfo::setName(const Name::Component& name)
+{
+  m_wire.reset();
+  m_name = name;
+}
+
+void
+ChatroomInfo::setTrustModel(const TrustModel trustModel)
+{
+  m_wire.reset();
+  m_trustModel = trustModel;
+}
+
+} //namespace chronos
diff --git a/src/chatroom-info.hpp b/src/chatroom-info.hpp
new file mode 100644
index 0000000..e182713
--- /dev/null
+++ b/src/chatroom-info.hpp
@@ -0,0 +1,135 @@
+/* -*- 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: Mengjin Yan <jane.yan0129@gmail.com>
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+#ifndef CHRONOCHAT_CHATROOM_INFO_HPP
+#define CHRONOCHAT_CHATROOM_INFO_HPP
+
+#include "common.hpp"
+#include "chatroom-tlv.hpp"
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/name-component.hpp>
+#include <ndn-cxx/util/time.hpp>
+#include <ndn-cxx/util/concepts.hpp>
+#include <ndn-cxx/encoding/block.hpp>
+#include <ndn-cxx/encoding/encoding-buffer.hpp>
+#include <ndn-cxx/exclude.hpp>
+#include <boost/concept_check.hpp>
+
+namespace chronos {
+
+/** \brief store a chatroom's information with encode and decode method.
+    \sa docs/design.rst
+ */
+
+class ChatroomInfo
+{
+
+public:
+
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : std::runtime_error(what)
+    {
+    }
+  };
+
+
+  enum TrustModel {
+    TRUST_MODEL_HIERARCHICAL = 2,
+    TRUST_MODEL_WEBOFTRUST = 1,
+    TRUST_MODEL_NONE = 0
+  };
+
+public:
+
+  ChatroomInfo();
+
+  explicit
+  ChatroomInfo(const Block& chatroomWire);
+
+  const Block&
+  wireEncode() const;
+
+  void
+  wireDecode(const Block& chatroomWire);
+
+  const Name::Component&
+  getName() const;
+
+  void
+  setName(const Name::Component& name);
+
+  const std::vector<Name>&
+  getParticipants() const;
+
+  void
+  addParticipant(const Name& participant);
+
+  const std::vector<Name>&
+  getContacts() const;
+
+  void
+  addContact(const Name& contact);
+
+  const TrustModel
+  getTrustModel() const;
+
+  void
+  setTrustModel(const TrustModel trustModel);
+
+private:
+  template<bool T>
+  size_t
+  wireEncode(ndn::EncodingImpl<T>& block) const;
+
+private:
+  mutable Block m_wire;
+  Name::Component m_name;
+  std::vector<Name> m_participants;
+  TrustModel m_trustModel;
+  std::vector<Name> m_contacts;
+
+};
+
+inline const Name::Component&
+ChatroomInfo::getName() const
+{
+  return m_name;
+}
+
+inline const std::vector<Name>&
+ChatroomInfo::getParticipants() const
+{
+  return m_participants;
+}
+
+inline const std::vector<Name>&
+ChatroomInfo::getContacts() const
+{
+  return m_contacts;
+}
+
+inline const ChatroomInfo::TrustModel
+ChatroomInfo::getTrustModel() const
+{
+  return m_trustModel;
+}
+
+BOOST_CONCEPT_ASSERT((ndn::WireEncodable<ChatroomInfo>));
+BOOST_CONCEPT_ASSERT((ndn::WireDecodable<ChatroomInfo>));
+
+
+} // namespace chronos
+
+#endif //CHRONOCHAT_CHATROOM_INFO_HPP
diff --git a/src/chatroom-tlv.hpp b/src/chatroom-tlv.hpp
new file mode 100644
index 0000000..954fbb5
--- /dev/null
+++ b/src/chatroom-tlv.hpp
@@ -0,0 +1,18 @@
+#ifndef CHRONOCHAT_CHATROOM_TLV_HPP
+#define CHRONOCHAT_CHATROOM_TLV_HPP
+
+namespace chronos {
+
+namespace tlv {
+
+enum {
+  PARTICIPANT = 128,
+  CHATROOM = 129,
+  TRUSTMODEL = 130
+};
+
+} //namespace tlv
+
+} //namespace chronos
+
+#endif //CHRONOCHAT_CHATROOM_TLV_HPP
diff --git a/src/controller.hpp b/src/controller.hpp
index d445171..6641b20 100644
--- a/src/controller.hpp
+++ b/src/controller.hpp
@@ -79,7 +79,7 @@
   onLocalPrefixTimeout(const Interest& interest);
 
   void
-  onInvitationInterestWrapper(const Name& prefix, const Interest& interest,
+  onInvitationInterestWrapper(const ndn::Name& prefix, const ndn::Interest& interest,
                               size_t routingPrefixOffset);
 
   void
@@ -182,7 +182,8 @@
   onError(const QString& msg);
 
   void
-  onInvitationInterest(const Name& prefix, const Interest& interest, size_t routingPrefixOffset);
+  onInvitationInterest(const ndn::Name& prefix, const ndn::Interest& interest,
+                       size_t routingPrefixOffset);
 
 private: // private member
   typedef std::map<std::string, QAction*> ChatActionList;
diff --git a/src/digest-tree-scene.cpp b/src/digest-tree-scene.cpp
index a253384..07e5dea 100644
--- a/src/digest-tree-scene.cpp
+++ b/src/digest-tree-scene.cpp
@@ -47,7 +47,7 @@
       // std::cout << "processUpdate v[" << i << "]: " << prefix.toStdString() << std::endl;
       rePlot = true;
       DisplayUserPtr p(new DisplayUser());
-      time_t tempTime = ::time(NULL) - FRESHNESS + 1;
+      time_t tempTime = ::time(0) + 1;
       p->setReceived(tempTime);
       p->setPrefix(prefix);
       p->setSeq(v[i].high);
@@ -115,7 +115,7 @@
     // std::cout << "Updating for prefix = " << prefix.toStdString() <<
     // " nick = " << nick.toStdString() << std::endl;
     DisplayUserPtr p = it.value();
-    p->setReceived(::time(NULL));
+    p->setReceived(::time(0) + 1);
     if (nick != p->getNick()) {
       // std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
       p->setNick(nick);
diff --git a/src/digest-tree-scene.hpp b/src/digest-tree-scene.hpp
index 434ee07..138f7f4 100644
--- a/src/digest-tree-scene.hpp
+++ b/src/digest-tree-scene.hpp
@@ -34,16 +34,17 @@
 class User;
 class DisplayUser;
 typedef boost::shared_ptr<DisplayUser> DisplayUserPtr;
+typedef QMap<QString, DisplayUserPtr> Roster;
+typedef QMap<QString, DisplayUserPtr>::iterator Roster_iterator;
+typedef QMapIterator<QString, DisplayUserPtr> RosterIterator;
+
 static DisplayUserPtr DisplayUserNullPtr;
 
+
 class DigestTreeScene : public QGraphicsScene
 {
   Q_OBJECT
 
-typedef QMap<QString, DisplayUserPtr> Roster;
-typedef QMap<QString, DisplayUserPtr>::iterator Roster_iterator;
-typedef QMapIterator<QString, DisplayUserPtr> RosterIterator;
-
 public:
   DigestTreeScene(QWidget *parent = 0);