Add TrustedContant and ContactStorage
Add tinyxml.py in waf-tools
diff --git a/src/contact-item.h b/src/contact-item.h
index 2940693..e681ba7 100644
--- a/src/contact-item.h
+++ b/src/contact-item.h
@@ -8,8 +8,8 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#ifndef CONTACT_ITEM_H
-#define CONTACT_ITEM_H
+#ifndef LINKNDN_CONTACT_ITEM_H
+#define LINKNDN_CONTACT_ITEM_H
 
 #include <ndn.cxx/data.h>
 #include <vector>
@@ -17,7 +17,7 @@
 
 class ContactItem
 {
-  typedef std::vector<Ptr<EndorseCertificate> > EndorseCertificateList;
+  typedef std::vector<ndn::Ptr<EndorseCertificate> > EndorseCertificateList;
 
 public:
   ContactItem(const EndorseCertificate& selfEndorseCertificate,
@@ -25,23 +25,31 @@
   
   ~ContactItem() {}
 
-  const ndn::Name&
+  inline const EndorseCertificate&
+  getSelfEndorseCertificate() const
+  { return m_selfEndorseCertificate; }
+
+  inline const ndn::Name&
   getNameSpace() const
   { return m_namespace; }
 
-  const std::string&
+  inline const std::string&
   getAlias() const
   { return m_alias; }
 
-  const std::string&
+  inline const std::string&
   getName() const
   { return m_name; }
 
-  const std::string&
+  inline const std::string&
   getInstitution() const
   { return m_institution; }
 
-private:
+  inline const ndn::Name
+  getPublicKeyName() const
+  { return m_selfEndorseCertificate.getPublicKeyName(); }
+
+protected:
   EndorseCertificate m_selfEndorseCertificate;
 
   ndn::Name m_namespace;
diff --git a/src/contact-storage.cpp b/src/contact-storage.cpp
new file mode 100644
index 0000000..f42ec21
--- /dev/null
+++ b/src/contact-storage.cpp
@@ -0,0 +1,215 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "contact-storage.h"
+#include "exception.h"
+
+#include <string>
+#include <boost/filesystem.hpp>
+
+using namespace std;
+using namespace ndn;
+namespace fs = boost::filesystem;
+
+
+const string INIT_TC_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  TrustedContact(                                                    \n \
+      contact_namespace BLOB NOT NULL,                               \n \
+      contact_alias     BLOB NOT NULL,                               \n \
+      self_certificate  BLOB NOT NULL,                               \n \
+      trust_scope       BLOB NOT NULL,                               \n \
+                                                                     \
+      PRIMARY KEY (contact_namespace)                                \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX tc_index ON TrustedContact(contact_namespace);          \n \
+";
+
+const string INIT_NC_TABLE = "\
+CREATE TABLE IF NOT EXISTS                                           \n \
+  NormalContact(                                                     \n \
+      contact_namespace BLOB NOT NULL,                               \n \
+      contact_alias     BLOB NOT NULL,                               \n \
+      self_certificate  BLOB NOT NULL,                               \n \
+                                                                     \
+      PRIMARY KEY (contact_namespace)                                \n \
+  );                                                                 \n \
+                                                                     \
+CREATE INDEX nc_index ON NormalContact(contact_namespace);           \n \
+";
+
+ContactStorage::ContactStorage()
+{
+  fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
+  fs::create_directories (chronosDir);
+
+  int res = sqlite3_open((chronosDir / "chronos.db").c_str (), &m_db);
+  if (res != SQLITE_OK)
+    throw LnException("Chronos DB cannot be open/created");
+
+  // Check if TrustedContact table exists
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='TrustedContact'", -1, &stmt, 0);
+  res = sqlite3_step (stmt);
+
+  bool tcTableExist = false;
+  if (res == SQLITE_ROW)
+      tcTableExist = true;
+  sqlite3_finalize (stmt);
+
+  if(!tcTableExist)
+    {
+      char *errmsg = 0;
+      res = sqlite3_exec (m_db, INIT_TC_TABLE.c_str (), NULL, NULL, &errmsg);
+      if (res != SQLITE_OK && errmsg != 0)
+        throw LnException("Init \"error\" in TrustedContact");
+      sqlite3_finalize (stmt);
+    }
+    
+  // Check if NormalContact table exists
+  sqlite3_prepare_v2 (m_db, "SELECT name FROM sqlite_master WHERE type='table' And name='NormalContact'", -1, &stmt, 0);
+  res = sqlite3_step (stmt);
+
+  bool ncTableExist = false;
+  if (res == SQLITE_ROW)
+      ncTableExist = true;
+  sqlite3_finalize (stmt);
+
+  if(!ncTableExist)
+    {
+      char *errmsg = 0;
+      res = sqlite3_exec (m_db, INIT_NC_TABLE.c_str (), NULL, NULL, &errmsg);
+        
+      if (res != SQLITE_OK && errmsg != 0)
+        throw LnException("Init \"error\" in NormalContact");
+    }
+}
+
+void
+ContactStorage::addTrustedContact(const TrustedContact& trustedContact)
+{
+  if(doesTrustedContactExist(trustedContact.getNameSpace()))
+    throw LnException("Trusted Contact has already existed");
+  
+  sqlite3_stmt *stmt;  
+  sqlite3_prepare_v2 (m_db, 
+                      "INSERT INTO TrustedContact (contact_namespace, contact_alias, self_certificate, trust_scope) values (?, ?, ?, ?)", 
+                      -1, 
+                      &stmt, 
+                      0);
+  
+  sqlite3_bind_text(stmt, 1, trustedContact.getNameSpace().toUri().c_str(),  trustedContact.getNameSpace().toUri().size (), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, trustedContact.getAlias().c_str(), trustedContact.getAlias().size(), SQLITE_TRANSIENT);
+  Ptr<Blob> selfCertificateBlob = trustedContact.getSelfEndorseCertificate().encodeToWire();
+  sqlite3_bind_text(stmt, 3, selfCertificateBlob->buf(), selfCertificateBlob->size(), SQLITE_TRANSIENT);
+  Ptr<Blob> trustScopeBlob = trustedContact.getTrustScopeBlob();
+  sqlite3_bind_text(stmt, 4, trustScopeBlob->buf(), trustScopeBlob->size(),SQLITE_TRANSIENT);
+
+  int res = sqlite3_step (stmt);
+  sqlite3_finalize (stmt);
+}
+  
+void
+ContactStorage::addNormalContact(const ContactItem& normalContact)
+{
+  if(doesNormalContactExist(normalContact.getNameSpace()))
+    throw LnException("Normal Contact has already existed");
+
+  sqlite3_stmt *stmt;  
+  sqlite3_prepare_v2 (m_db, 
+                      "INSERT INTO NormalContact (contact_namespace, contact_alias, self_certificate) values (?, ?, ?)", 
+                      -1, 
+                      &stmt, 
+                      0);
+
+  sqlite3_bind_text(stmt, 1, normalContact.getNameSpace().toUri().c_str(),  normalContact.getNameSpace().toUri().size (), SQLITE_TRANSIENT);
+  sqlite3_bind_text(stmt, 2, normalContact.getAlias().c_str(), normalContact.getAlias().size(), SQLITE_TRANSIENT);
+  Ptr<Blob> selfCertificateBlob = normalContact.getSelfEndorseCertificate().encodeToWire();
+  sqlite3_bind_text(stmt, 3, selfCertificateBlob->buf(), selfCertificateBlob->size(), SQLITE_TRANSIENT);
+
+  int res = sqlite3_step (stmt);
+  sqlite3_finalize (stmt);
+}
+
+bool
+ContactStorage::doesContactExist(const Name& name, bool normal)
+{
+  bool result = false;
+  
+  sqlite3_stmt *stmt;
+  if(normal)
+    sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM NormalContact WHERE contact_namespace=?", -1, &stmt, 0);
+  else
+    sqlite3_prepare_v2 (m_db, "SELECT count(*) FROM TrustedContact WHERE contact_namespace=?", -1, &stmt, 0);
+  sqlite3_bind_text(stmt, 1, name.toUri().c_str(), name.toUri().size(), SQLITE_TRANSIENT);
+
+  int res = sqlite3_step (stmt);
+    
+  if (res == SQLITE_ROW)
+    {
+      int countAll = sqlite3_column_int (stmt, 0);
+      if (countAll > 0)
+        result = true;
+    } 
+  sqlite3_finalize (stmt); 
+  return result;
+}
+
+vector<Ptr<TrustedContact> >
+ContactStorage::getAllTrustedContacts() const
+{
+  vector<Ptr<TrustedContact> > trustedContacts;
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, 
+                      "SELECT contact_alias, self_certificate, trust_scope FROM TrustedContact", 
+                      -1, 
+                      &stmt, 
+                      0);
+  
+  while( sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      string alias(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      Ptr<Blob> certBlob = Ptr<Blob>(new Blob(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1)));
+      Ptr<Data> certData = Data::decodeFromWire(certBlob);
+      EndorseCertificate endorseCertificate(*certData);
+      string trustScope(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 2)), sqlite3_column_bytes (stmt, 2));
+
+      trustedContacts.push_back(Ptr<TrustedContact>(new TrustedContact(endorseCertificate, trustScope, alias)));      
+    }
+
+  return trustedContacts;
+}
+
+vector<Ptr<ContactItem> >
+ContactStorage::getAllNormalContacts() const
+{
+  vector<Ptr<ContactItem> > normalContacts;
+
+  sqlite3_stmt *stmt;
+  sqlite3_prepare_v2 (m_db, 
+                      "SELECT contact_alias, self_certificate FROM NormalContact", 
+                      -1, 
+                      &stmt, 
+                      0);
+  
+  while( sqlite3_step (stmt) == SQLITE_ROW)
+    {
+      string alias(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 0)), sqlite3_column_bytes (stmt, 0));
+      Ptr<Blob> certBlob = Ptr<Blob>(new Blob(reinterpret_cast<const char *>(sqlite3_column_text(stmt, 1)), sqlite3_column_bytes (stmt, 1)));
+      Ptr<Data> certData = Data::decodeFromWire(certBlob);
+      EndorseCertificate endorseCertificate(*certData);
+
+      normalContacts.push_back(Ptr<ContactItem>(new ContactItem(endorseCertificate, alias)));      
+    }
+  
+  return normalContacts;
+}
diff --git a/src/contact-storage.h b/src/contact-storage.h
new file mode 100644
index 0000000..eca65da
--- /dev/null
+++ b/src/contact-storage.h
@@ -0,0 +1,53 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef LINKNDN_CONTACT_STORAGE_H
+#define LINKNDN_CONTACT_STORAGE_H
+
+#include <sqlite3.h>
+#include "trusted-contact.h"
+#include "contact-item.h"
+
+class ContactStorage
+{
+public:
+  ContactStorage();
+  
+  ~ContactStorage() {}
+
+  void
+  addTrustedContact(const TrustedContact& trustedContact);
+  
+  void
+  addNormalContact(const ContactItem& contactItem);
+
+  std::vector<ndn::Ptr<TrustedContact> >
+  getAllTrustedContacts() const;
+
+  std::vector<ndn::Ptr<ContactItem> >
+  getAllNormalContacts() const;
+
+private:
+  inline bool
+  doesTrustedContactExist(const ndn::Name& name)
+  { return doesContactExist(name, false); }
+
+  inline bool
+  doesNormalContactExist(const ndn::Name& name)
+  { return doesContactExist(name, true); }
+
+  bool
+  doesContactExist(const ndn::Name& name, bool normal);
+  
+private:
+  sqlite3 *m_db;
+};
+
+#endif
diff --git a/src/trusted-contact.cpp b/src/trusted-contact.cpp
new file mode 100644
index 0000000..b3271d2
--- /dev/null
+++ b/src/trusted-contact.cpp
@@ -0,0 +1,56 @@
+/* -*- 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 "trusted-contact.h"
+#include <tinyxml.h>
+
+using namespace std;
+using namespace ndn;
+
+TrustedContact::TrustedContact(const EndorseCertificate& selfEndorseCertificate,
+			       const string& trustScope,
+			       const string& alias)
+  : ContactItem(selfEndorseCertificate, alias)
+{
+  TiXmlDocument xmlDoc;
+  xmlDoc.Parse(trustScope.c_str());
+  
+  TiXmlNode * it = xmlDoc.FirstChild();    
+  while(it != NULL)
+    {
+      m_trustScope.push_back(Regex::fromXmlElement(dynamic_cast<TiXmlElement *>(it)));
+      it = it->NextSibling();
+    }
+}
+
+bool 
+TrustedContact::canBeTrustedFor(const Name& name)
+{
+  vector<Ptr<Regex> >::iterator it = m_trustScope.begin();
+
+  for(; it != m_trustScope.end(); it++)
+    if((*it)->match(name))
+      return true;
+  return false;
+}
+
+Ptr<Blob> 
+TrustedContact::getTrustScopeBlob() const
+{
+  ostringstream oss;
+  TiXmlDocument * xmlDoc = new TiXmlDocument();
+
+  vector<Ptr<Regex> >::const_iterator it = m_trustScope.begin();
+  for(; it != m_trustScope.end(); it++)
+      xmlDoc->LinkEndChild((*it)->toXmlElement());
+
+  oss << *xmlDoc;
+  return Ptr<Blob>(new Blob(oss.str().c_str(), oss.str().size()));
+}
diff --git a/src/trusted-contact.h b/src/trusted-contact.h
new file mode 100644
index 0000000..9f9121c
--- /dev/null
+++ b/src/trusted-contact.h
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef LINKNDN_TRUSTED_CONTACT_H
+#define LINKNDN_TRUSTED_CONTACT_H
+
+#include "contact-item.h"
+#include <ndn.cxx/regex/regex.h>
+
+class TrustedContact : public ContactItem
+{
+public:
+  TrustedContact(const EndorseCertificate& selfEndorseCertificate,
+                 const std::string& trustScope,
+                 const std::string& alias = std::string());
+
+  ~TrustedContact() {}
+
+  void
+  addTrustScope(ndn::Ptr<ndn::Regex> nameSpace)
+  { m_trustScope.push_back(nameSpace); }
+
+  bool
+  canBeTrustedFor(const ndn::Name& name);
+
+  ndn::Ptr<ndn::Blob> 
+  getTrustScopeBlob() const;
+
+private:
+  std::vector<ndn::Ptr<ndn::Regex> > m_trustScope;
+};
+
+#endif
diff --git a/waf-tools/tinyxml.py b/waf-tools/tinyxml.py
new file mode 100644
index 0000000..3908b38
--- /dev/null
+++ b/waf-tools/tinyxml.py
@@ -0,0 +1,76 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+'''
+
+When using this tool, the wscript will look like:
+
+	def options(opt):
+	        opt.tool_options('tinyxml', tooldir=["waf-tools"])
+
+	def configure(conf):
+		conf.load('compiler_cxx tiny')
+
+	def build(bld):
+		bld(source='main.cpp', target='app', use='TINYXML')
+
+Options are generated, in order to specify the location of tinyxml includes/libraries.
+
+
+'''
+import sys
+import re
+from waflib import Utils,Logs,Errors
+from waflib.Configure import conf
+TINYXML_DIR=['/usr','/usr/local','/opt/local','/sw']
+TINYXML_VERSION_FILE='tinyxml.h'
+TINYXML_VERSION_CODE='''
+#include <iostream>
+#include <tinyxml.h>
+int main() { std::cout << TIXML_MAJOR_VERSION << "." << TIXML_MINOR_VERSION << "." << TIXML_PATCH_VERSION; }
+'''
+
+def options(opt):
+	opt.add_option('--tinyxml',type='string',default='',dest='tinyxml_dir',help='''path to where TinyXML is installed, e.g. /usr/local''')
+@conf
+def __tinyxml_get_version_file(self,dir):
+	try:
+		return self.root.find_dir(dir).find_node('%s/%s' % ('include', TINYXML_VERSION_FILE))
+	except:
+		return None
+@conf
+def tinyxml_get_version(self,dir):
+	val=self.check_cxx(fragment=TINYXML_VERSION_CODE,includes=['%s/%s' % (dir, 'include')], execute=True, define_ret = True, mandatory=True)
+	return val
+@conf
+def tinyxml_get_root(self,*k,**kw):
+	root=k and k[0]or kw.get('path',None)
+	# Logs.pprint ('RED', '   %s' %root)
+	if root and self.__tinyxml_get_version_file(root):
+		return root
+	for dir in TINYXML_DIR:
+		if self.__tinyxml_get_version_file(dir):
+			return dir
+	if root:
+		self.fatal('TinyXML not found in %s'%root)
+	else:
+		self.fatal('TinyXML not found, please provide a --tinyxml argument (see help)')
+@conf
+def check_tinyxml(self,*k,**kw):
+	if not self.env['CXX']:
+		self.fatal('load a c++ compiler first, conf.load("compiler_cxx")')
+
+	var=kw.get('uselib_store','TINYXML')
+	self.start_msg('Checking TinyXML')
+	root = self.tinyxml_get_root(*k,**kw);
+	self.env.TINYXML_VERSION=self.tinyxml_get_version(root)
+
+	self.env['INCLUDES_%s'%var]= '%s/%s' % (root, "include");
+	self.env['LIB_%s'%var] = "tinyxml"
+	self.env['LIBPATH_%s'%var] = '%s/%s' % (root, "lib")
+
+	self.end_msg(self.env.TINYXML_VERSION)
+	if Logs.verbose:
+		Logs.pprint('CYAN','	TinyXML include : %s'%self.env['INCLUDES_%s'%var])
+		Logs.pprint('CYAN','	TinyXML lib     : %s'%self.env['LIB_%s'%var])
+		Logs.pprint('CYAN','	TinyXML libpath : %s'%self.env['LIBPATH_%s'%var])
diff --git a/wscript b/wscript
index 15f0fcf..c949474 100644
--- a/wscript
+++ b/wscript
@@ -6,22 +6,19 @@
 
 def options(opt):
     opt.load('compiler_c compiler_cxx boost protoc qt4')
+
+    opt.load('tinyxml', tooldir=['waf-tools'])
     
 def configure(conf):
-    conf.load("compiler_c compiler_cxx")
+    conf.load("compiler_c compiler_cxx boost protoc qt4 tinyxml")
 
     conf.add_supported_cxxflags (cxxflags = ['-O3', '-g'])
 
-    conf.load('protoc')
-
-    conf.load('qt4')
-
-    conf.load('boost')
-
+    conf.check_tinyxml(path=conf.options.tinyxml_dir)
     conf.check_cfg(package='libndn.cxx', args=['--cflags', '--libs'], uselib_store='NDNCXX', mandatory=True)
     conf.check_cfg(package='sqlite3', args=['--cflags', '--libs'], uselib_store='SQLITE3', mandatory=True)
 
-    conf.check_boost(lib='system random thread')
+    conf.check_boost(lib='system random thread filesystem')
 
     conf.write_config_header('config.h')
 
@@ -33,7 +30,7 @@
         defines = "WAF",
         source = bld.path.ant_glob(['src/*.cpp', 'src/*.ui']),
         includes = ".",
-        use = "QTCORE QTGUI SQLITE3 NDNCXX",
+        use = "QTCORE QTGUI SQLITE3 NDNCXX TINYXML BOOST BOOST_FILESYSTEM",
         )