check and update roster
diff --git a/chatdialog.cpp b/chatdialog.cpp
index 81237e2..abf6005 100644
--- a/chatdialog.cpp
+++ b/chatdialog.cpp
@@ -11,31 +11,8 @@
 
 #define BROADCAST_PREFIX_FOR_SYNC_DEMO "/ndn/broadcast/sync-demo"
 
-static const int FRESHNESS = 120;  // seconds
 static const int HELLO_INTERVAL = 90;  // seconds
 
-void
-ChatDialog::testDraw()
-{
-  std::string prefix[5] = {"/ndn/1", "/ndn/2", "/ndn/3", "/ndn/4", "/ndn/5"};
-  std::string nick[5] = {"tom", "jerry", "jason", "michael", "hurry"};
-  std::vector<Sync::MissingDataInfo> v;
-  for (int i = 0; i < 5; i++)
-  {
-    Sync::MissingDataInfo mdi = {prefix[i], Sync::SeqNo(0), Sync::SeqNo(i * (2 << i) )};
-    v.push_back(mdi);
-  }
-
-  m_scene->processUpdate(v, "12341234@!#%!@");
-
-  for (int i = 0; i < 5; i++)
-  {
-   m_scene-> msgReceived(prefix[i].c_str(), nick[i].c_str());
-  }
-
-  fitView();
-}
-
 ChatDialog::ChatDialog(QWidget *parent)
   : QDialog(parent), m_sock(NULL), m_lastMsgTime(0)
 {
@@ -61,6 +38,19 @@
   QRectF rect = m_scene->itemsBoundingRect();
   m_scene->setSceneRect(rect);
 
+  createActions();
+  createTrayIcon();
+  m_timer = new QTimer(this);
+  connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
+  connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
+  connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool)), this, SLOT(processData(QString, const char *, size_t, bool)));
+  connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
+  connect(this, SIGNAL(removeReceived(QString)), this, SLOT(processRemove(QString)));
+  connect(m_timer, SIGNAL(timeout()), this, SLOT(replot()));
+  connect(m_scene, SIGNAL(replot()), this, SLOT(replot()));
+  connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
+  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
+
   // create sync socket
   if(!m_user.getChatroom().isEmpty()) {
     std::string syncPrefix = BROADCAST_PREFIX_FOR_SYNC_DEMO;
@@ -70,6 +60,7 @@
     {
       m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
       sendHello();
+      m_timer->start(FRESHNESS * 2000);
     }
     catch (Sync::CcnxOperationException ex)
     {
@@ -78,16 +69,6 @@
     }
   }
   
-  createActions();
-  createTrayIcon();
-  connect(lineEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
-  connect(setButton, SIGNAL(pressed()), this, SLOT(buttonPressed()));
-  connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool)), this, SLOT(processData(QString, const char *, size_t, bool)));
-  connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
-  connect(this, SIGNAL(removeReceived(QString)), this, SLOT(processRemove(QString)));
-  connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(showNormal()));
-  connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
-
 //testDraw();
 }
 
@@ -101,6 +82,13 @@
   }
 }
 
+void
+ChatDialog::replot()
+{
+  boost::mutex::scoped_lock lock(m_sceneMutex);
+  m_scene->plot(m_sock->getRootDigest().c_str());
+}
+
 void 
 ChatDialog::setVisible(bool visible)
 {
@@ -334,6 +322,7 @@
   bool removed = m_scene->removeNode(prefix);
   if (removed)
   {
+    boost::mutex::scoped_lock lock(m_sceneMutex);
     m_scene->plot(m_sock->getRootDigest().c_str());
   }
 }
@@ -536,6 +525,7 @@
     {
       m_sock = new Sync::SyncAppSocket(syncPrefix, bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2), bind(&ChatDialog::processRemoveWrapper, this, _1));
       sendHello();
+      m_timer->start(FRESHNESS * 2000);
     }
     catch (Sync::CcnxOperationException ex)
     {
diff --git a/chatdialog.h b/chatdialog.h
index 8846a4b..5662b7b 100644
--- a/chatdialog.h
+++ b/chatdialog.h
@@ -61,6 +61,7 @@
   void checkSetting();
   void settingUpdated(QString, QString, QString);
   void sendHello();
+  void replot();
 
   // icon related
   void iconActivated(QSystemTrayIcon::ActivationReason reason);
@@ -81,6 +82,7 @@
   boost::mutex m_sceneMutex;
   time_t m_lastMsgTime;
   int m_randomizedInterval;
+  QTimer *m_timer;
 
   // icon related
   QAction *minimizeAction;
diff --git a/digesttreescene.cpp b/digesttreescene.cpp
index b0b3d7c..2bb1c53 100644
--- a/digesttreescene.cpp
+++ b/digesttreescene.cpp
@@ -8,7 +8,6 @@
 
 static const double Pi = 3.14159265358979323846264338327950288419717;
 
-
 DigestTreeScene::DisplayUserPtr DigestTreeScene::DisplayUserNullPtr;
 
 DigestTreeScene::DigestTreeScene(QWidget *parent)
@@ -29,6 +28,8 @@
     {
       rePlot = true; 
       DisplayUserPtr p(new DisplayUser());
+      time_t tempTime = time(NULL) - 2 * FRESHNESS + 1;
+      p->setReceived(tempTime);
       p->setPrefix(v[i].prefix.c_str());
       p->setSeq(v[i].high);
       m_roster.insert(p->getPrefix(), p);
@@ -42,6 +43,7 @@
   if (rePlot) 
   {
     plot(digest);
+    QTimer::singleShot(2100, this, SLOT(emitReplot()));
   }
   else 
   {
@@ -64,6 +66,12 @@
 }
 
 void
+DigestTreeScene::emitReplot()
+{
+  emit replot();
+}
+
+void
 DigestTreeScene::msgReceived(QString prefix, QString nick)
 {
 #ifdef __DEBUG
@@ -73,6 +81,7 @@
   if (it != m_roster.end()) 
   {
     DisplayUserPtr p = it.value();
+    p->setReceived(time(NULL));
     if (nick != p->getNick()) {
       p->setNick(nick);
       QGraphicsTextItem *nickItem = p->getNickTextItem();
@@ -123,6 +132,9 @@
 void
 DigestTreeScene::plot(QString digest)
 {
+#ifdef __DEBUG
+  std::cout << "Plotting at time: " << time(NULL) << std::endl;
+#endif
   clear();
 
   int nodeSize = 40;
@@ -132,6 +144,34 @@
   layout->setSiblingDistance(siblingDistance);
   layout->setLevelDistance(levelDistance);
 
+  // do some cleaning, get rid of stale member info
+  Roster_iterator it = m_roster.begin();
+  while (it != m_roster.end())
+  {
+    DisplayUserPtr p = it.value();
+    if (p != DisplayUserNullPtr)
+    {
+      time_t now = time(NULL);
+      if (now - p->getReceived() >= FRESHNESS * 2)
+      {
+#ifdef __DEBUG
+        std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
+        std::cout << "now - last = " << now - p->getReceived() << std::endl;
+#endif
+        p = DisplayUserNullPtr;
+        it = m_roster.erase(it);
+      }
+      else
+      {
+        ++it;
+      }
+    }
+    else
+    {
+      it = m_roster.erase(it);
+    }
+  }
+
   int n = m_roster.size();
   std::vector<TreeLayout::Coordinate> childNodesCo(n);
 
diff --git a/digesttreescene.h b/digesttreescene.h
index 6a30e18..0a385e0 100644
--- a/digesttreescene.h
+++ b/digesttreescene.h
@@ -11,6 +11,8 @@
 #include <QColor>
 #include "treelayout.h"
 
+const int FRESHNESS = 120;
+
 class QGraphicsTextItem;
 
 class User;
@@ -31,8 +33,15 @@
   void processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest);
   void msgReceived(QString prefix, QString nick);
   void clearAll();
-  void plot(QString digest);
   bool removeNode(const QString prefix);
+  void plot(QString digest);
+
+signals:
+  void replot();
+
+private slots:
+  void emitReplot();
+
 private:
   void plotEdge(const std::vector<TreeLayout::Coordinate> &v, int nodeSize);
   void plotNode(const std::vector<TreeLayout::Coordinate> &v, QString digest, int nodeSize);
@@ -53,7 +62,7 @@
   void setPrefix(QString prefix) {m_prefix = prefix;}
   void setChatroom(QString chatroom) {m_chatroom = chatroom;}
   void setSeq(Sync::SeqNo seq) {m_seq = seq;}
-  void setReceived() {m_received = time(NULL);}
+  void setReceived(time_t t) {m_received = t;}
   QString getNick() { return m_nick;}
   QString getPrefix() { return m_prefix;}
   QString getChatroom() { return m_chatroom;}