blob: d59a7077246d92b4a4d4eee6a1802aee82698d76 [file] [log] [blame]
Yingdi Yud04ed1a2013-10-14 14:07:03 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
Qiuhan Ding0cfc1512015-02-17 17:44:11 -08009 * Author: Qiuhan Ding <qiuhanding@cs.ucla.edu>
Yingdi Yud04ed1a2013-10-14 14:07:03 -070010 */
11
Yingdi Yu0b0a7362014-08-05 16:31:30 -070012#include "contact-storage.hpp"
Yingdi Yud04ed1a2013-10-14 14:07:03 -070013
Yingdi Yud04ed1a2013-10-14 14:07:03 -070014#include <boost/filesystem.hpp>
Yingdi Yu0b0a7362014-08-05 16:31:30 -070015#include "cryptopp.hpp"
Yingdi Yu3b318c12013-10-15 17:54:00 -070016#include "logging.h"
Yingdi Yud04ed1a2013-10-14 14:07:03 -070017
Yingdi Yu0b0a7362014-08-05 16:31:30 -070018
Qiuhan Ding0cfc1512015-02-17 17:44:11 -080019// INIT_LOGGER ("chronochat.ContactStorage");
Yingdi Yu0b0a7362014-08-05 16:31:30 -070020
Yingdi Yueb692ac2015-02-10 18:46:18 -080021namespace chronochat {
Yingdi Yu0b0a7362014-08-05 16:31:30 -070022
Yingdi Yud04ed1a2013-10-14 14:07:03 -070023namespace fs = boost::filesystem;
24
Yingdi Yu0b0a7362014-08-05 16:31:30 -070025using std::string;
26using std::vector;
Yingdi Yu3b318c12013-10-15 17:54:00 -070027
Yingdi Yu0b0a7362014-08-05 16:31:30 -070028using ndn::PublicKey;
Yingdi Yufa4ce792014-02-06 18:09:22 -080029
Yingdi Yu0b0a7362014-08-05 16:31:30 -070030// user's own profile;
31const string INIT_SP_TABLE =
32 "CREATE TABLE IF NOT EXISTS "
33 " SelfProfile( "
34 " profile_type BLOB NOT NULL, "
35 " profile_value BLOB NOT NULL, "
36 " PRIMARY KEY (profile_type) "
37 " ); "
38 "CREATE INDEX sp_index ON SelfProfile(profile_type); ";
Yingdi Yu17032f82014-03-25 15:48:23 -070039
Yingdi Yu0b0a7362014-08-05 16:31:30 -070040// user's self endorse cert;
41const string INIT_SE_TABLE =
42 "CREATE TABLE IF NOT EXISTS "
43 " SelfEndorse( "
44 " identity BLOB NOT NULL UNIQUE, "
45 " endorse_data BLOB NOT NULL, "
46 " PRIMARY KEY (identity) "
47 " ); "
48 "CREATE INDEX se_index ON SelfEndorse(identity); ";
Yingdi Yu3b318c12013-10-15 17:54:00 -070049
Yingdi Yu0b0a7362014-08-05 16:31:30 -070050// contact's basic info
51const string INIT_CONTACT_TABLE =
52 "CREATE TABLE IF NOT EXISTS "
53 " Contact( "
54 " contact_namespace BLOB NOT NULL, "
55 " contact_alias BLOB NOT NULL, "
56 " contact_keyName BLOB NOT NULL, "
57 " contact_key BLOB NOT NULL, "
58 " notBefore INTEGER DEFAULT 0, "
59 " notAfter INTEGER DEFAULT 0, "
60 " is_introducer INTEGER DEFAULT 0, "
61 " PRIMARY KEY (contact_namespace) "
62 " ); "
63 "CREATE INDEX contact_index ON Contact(contact_namespace); ";
Yingdi Yud04ed1a2013-10-14 14:07:03 -070064
Yingdi Yu0b0a7362014-08-05 16:31:30 -070065// contact's trust scope;
66const string INIT_TS_TABLE =
67 "CREATE TABLE IF NOT EXISTS "
68 " TrustScope( "
69 " id INTEGER PRIMARY KEY AUTOINCREMENT, "
70 " contact_namespace BLOB NOT NULL, "
71 " trust_scope BLOB NOT NULL "
72 " ); "
73 "CREATE INDEX ts_index ON TrustScope(contact_namespace); ";
Yingdi Yud04ed1a2013-10-14 14:07:03 -070074
Yingdi Yu0b0a7362014-08-05 16:31:30 -070075// contact's profile
76const string INIT_CP_TABLE =
77 "CREATE TABLE IF NOT EXISTS "
78 " ContactProfile( "
79 " profile_identity BLOB NOT NULL, "
80 " profile_type BLOB NOT NULL, "
81 " profile_value BLOB NOT NULL, "
82 " endorse INTEGER NOT NULL, "
83 " PRIMARY KEY (profile_identity, profile_type) "
84 " ); "
85 "CREATE INDEX cp_index ON ContactProfile(profile_identity); ";
Yingdi Yub2e747d2013-11-05 23:06:43 -080086
Yingdi Yu0b0a7362014-08-05 16:31:30 -070087// user's endorsement on contacts
88const string INIT_PE_TABLE =
89 "CREATE TABLE IF NOT EXISTS "
90 " ProfileEndorse( "
91 " identity BLOB NOT NULL UNIQUE, "
92 " endorse_data BLOB NOT NULL, "
93 " PRIMARY KEY (identity) "
94 " ); "
95 "CREATE INDEX pe_index ON ProfileEndorse(identity); ";
Yingdi Yub2e747d2013-11-05 23:06:43 -080096
Yingdi Yu0b0a7362014-08-05 16:31:30 -070097// contact's endorsements on the user
98const string INIT_CE_TABLE =
99 "CREATE TABLE IF NOT EXISTS "
100 " CollectEndorse( "
101 " endorser BLOB NOT NULL, "
102 " endorse_name BLOB NOT NULL, "
103 " endorse_data BLOB NOT NULL, "
104 " PRIMARY KEY (endorser) "
105 " ); ";
Yingdi Yub2e747d2013-11-05 23:06:43 -0800106
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700107// dns data;
108const string INIT_DD_TABLE =
109 "CREATE TABLE IF NOT EXISTS "
110 " DnsData( "
111 " dns_name BLOB NOT NULL, "
112 " dns_type BLOB NOT NULL, "
113 " data_name BLOB NOT NULL, "
114 " dns_value BLOB NOT NULL, "
115 " PRIMARY KEY (dns_name, dns_type) "
116 " ); "
117 "CREATE INDEX dd_index ON DnsData(dns_name, dns_type); "
118 "CREATE INDEX dd_index2 ON DnsData(data_name); ";
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700119
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700120/**
121 * A utility function to call the normal sqlite3_bind_text where the value and length are
122 * value.c_str() and value.size().
123 */
124static int
125sqlite3_bind_string(sqlite3_stmt* statement,
126 int index,
127 const string& value,
128 void(*destructor)(void*))
129{
130 return sqlite3_bind_text(statement, index, value.c_str(), value.size(), destructor);
131}
132
133/**
134 * A utility function to call the normal sqlite3_bind_blob where the value and length are
135 * block.wire() and block.size().
136 */
137static int
138sqlite3_bind_block(sqlite3_stmt* statement,
139 int index,
140 const Block& block,
141 void(*destructor)(void*))
142{
143 return sqlite3_bind_blob(statement, index, block.wire(), block.size(), destructor);
144}
145
146/**
147 * A utility function to generate string by calling the normal sqlite3_column_text.
148 */
149static string
150sqlite3_column_string(sqlite3_stmt* statement, int column)
151{
152 return string(reinterpret_cast<const char*>(sqlite3_column_text(statement, column)),
153 sqlite3_column_bytes(statement, column));
154}
155
156/**
157 * A utility function to generate block by calling the normal sqlite3_column_text.
158 */
159static Block
160sqlite3_column_block(sqlite3_stmt* statement, int column)
161{
162 return Block(reinterpret_cast<const char*>(sqlite3_column_blob(statement, column)),
163 sqlite3_column_bytes(statement, column));
164}
165
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800166
167ContactStorage::ContactStorage(const Name& identity)
168 : m_identity(identity)
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700169{
170 fs::path chronosDir = fs::path(getenv("HOME")) / ".chronos";
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700171 fs::create_directories(chronosDir);
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700172
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700173 int res = sqlite3_open((chronosDir / getDBName()).c_str(), &m_db);
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700174 if (res != SQLITE_OK)
Yingdi Yueb692ac2015-02-10 18:46:18 -0800175 throw Error("chronochat DB cannot be open/created");
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700176
Yingdi Yufa4ce792014-02-06 18:09:22 -0800177 initializeTable("SelfProfile", INIT_SP_TABLE);
178 initializeTable("SelfEndorse", INIT_SE_TABLE);
179 initializeTable("Contact", INIT_CONTACT_TABLE);
180 initializeTable("TrustScope", INIT_TS_TABLE);
181 initializeTable("ContactProfile", INIT_CP_TABLE);
182 initializeTable("ProfileEndorse", INIT_PE_TABLE);
183 initializeTable("CollectEndorse", INIT_CE_TABLE);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800184 initializeTable("DnsData", INIT_DD_TABLE);
Yingdi Yu3b318c12013-10-15 17:54:00 -0700185
Yingdi Yu3b318c12013-10-15 17:54:00 -0700186}
187
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700188string
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800189ContactStorage::getDBName()
190{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700191 string dbName("chronos-");
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800192
Yingdi Yu17032f82014-03-25 15:48:23 -0700193 std::stringstream ss;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800194 {
195 using namespace CryptoPP;
196
197 SHA256 hash;
198 StringSource(m_identity.wireEncode().wire(), m_identity.wireEncode().size(), true,
199 new HashFilter(hash, new HexEncoder(new FileSink(ss), false)));
200 }
201 dbName.append(ss.str()).append(".db");
202
203 return dbName;
204}
205
Yingdi Yu3b318c12013-10-15 17:54:00 -0700206void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700207ContactStorage::initializeTable(const string& tableName, const string& sqlCreateStmt)
Yingdi Yu3b318c12013-10-15 17:54:00 -0700208{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800209 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700210 sqlite3_prepare_v2(m_db,
211 "SELECT name FROM sqlite_master WHERE type='table' And name=?",
212 -1, &stmt, 0);
213 sqlite3_bind_string(stmt, 1, tableName, SQLITE_TRANSIENT);
214 int res = sqlite3_step(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800215
216 bool tableExist = false;
217 if (res == SQLITE_ROW)
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700218 tableExist = true;
219 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800220
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700221 if (!tableExist) {
222 char *errmsg = 0;
223 res = sqlite3_exec(m_db, sqlCreateStmt.c_str (), NULL, NULL, &errmsg);
224 if (res != SQLITE_OK && errmsg != 0)
225 throw Error("Init \"error\" in " + tableName);
226 }
Yingdi Yu3b318c12013-10-15 17:54:00 -0700227}
228
Yingdi Yu76dd8002013-12-24 11:16:32 +0800229shared_ptr<Profile>
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800230ContactStorage::getSelfProfile()
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700231{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800232 shared_ptr<Profile> profile = make_shared<Profile>(m_identity);
Yingdi Yu3b318c12013-10-15 17:54:00 -0700233 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700234 sqlite3_prepare_v2(m_db, "SELECT profile_type, profile_value FROM SelfProfile", -1, &stmt, 0);
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700235
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700236 while (sqlite3_step(stmt) == SQLITE_ROW) {
237 string profileType = sqlite3_column_string(stmt, 0);
238 string profileValue = sqlite3_column_string (stmt, 1);
239 (*profile)[profileType] = profileValue;
240 }
Yingdi Yu72781e52013-11-06 23:00:21 -0800241 sqlite3_finalize(stmt);
242
Yingdi Yu3b318c12013-10-15 17:54:00 -0700243 return profile;
244}
Yingdi Yuae8217c2013-11-09 00:03:26 -0800245
Yingdi Yufa4ce792014-02-06 18:09:22 -0800246void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800247ContactStorage::addSelfEndorseCertificate(const EndorseCertificate& newEndorseCertificate)
Yingdi Yufa4ce792014-02-06 18:09:22 -0800248{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800249 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700250 sqlite3_prepare_v2(m_db,
251 "INSERT OR REPLACE INTO SelfEndorse (identity, endorse_data) values (?, ?)",
252 -1, &stmt, 0);
253 sqlite3_bind_string(stmt, 1, m_identity.toUri(), SQLITE_TRANSIENT);
254 sqlite3_bind_block(stmt, 2, newEndorseCertificate.wireEncode(), SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700255 sqlite3_step(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800256
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700257 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800258}
259
Yingdi Yufa4ce792014-02-06 18:09:22 -0800260void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700261ContactStorage::addEndorseCertificate(const EndorseCertificate& endorseCertificate,
262 const Name& identity)
Yingdi Yufa4ce792014-02-06 18:09:22 -0800263{
Yingdi Yufa4ce792014-02-06 18:09:22 -0800264 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700265 sqlite3_prepare_v2(m_db,
266 "INSERT OR REPLACE INTO ProfileEndorse \
267 (identity, endorse_data) values (?, ?)",
268 -1, &stmt, 0);
269 sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
270 sqlite3_bind_block(stmt, 2, endorseCertificate.wireEncode(), SQLITE_TRANSIENT);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800271 sqlite3_step(stmt);
272
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700273 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800274}
275
276void
277ContactStorage::updateCollectEndorse(const EndorseCertificate& endorseCertificate)
278{
279 Name endorserName = endorseCertificate.getSigner();
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800280 Name certName = endorseCertificate.getName();
Yingdi Yufa4ce792014-02-06 18:09:22 -0800281
282 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700283 sqlite3_prepare_v2(m_db,
284 "INSERT OR REPLACE INTO CollectEndorse \
285 (endorser, endorse_name, endorse_data) \
286 VALUES (?, ?, ?, ?)",
287 -1, &stmt, 0);
288 sqlite3_bind_string(stmt, 1, endorserName.toUri(), SQLITE_TRANSIENT);
289 sqlite3_bind_string(stmt, 2, certName.toUri(), SQLITE_TRANSIENT);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700290 sqlite3_bind_block(stmt, 3, endorseCertificate.wireEncode(), SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700291 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700292 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800293 return;
294}
295
296void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800297ContactStorage::getCollectEndorse(EndorseCollection& endorseCollection)
Yingdi Yufa4ce792014-02-06 18:09:22 -0800298{
299 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700300 sqlite3_prepare_v2(m_db, "SELECT endorse_name, endorse_data FROM CollectEndorse", -1, &stmt, 0);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800301
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700302 while (sqlite3_step(stmt) == SQLITE_ROW) {
303 string certName = sqlite3_column_string(stmt, 0);
304 std::stringstream ss;
Yingdi Yufa4ce792014-02-06 18:09:22 -0800305 {
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700306 using namespace CryptoPP;
307 SHA256 hash;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800308
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700309 StringSource(sqlite3_column_text(stmt, 1), sqlite3_column_bytes (stmt, 1), true,
310 new HashFilter(hash, new FileSink(ss)));
Yingdi Yufa4ce792014-02-06 18:09:22 -0800311 }
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800312 endorseCollection.addCollectionEntry(Name(certName), ss.str());
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700313 }
Yingdi Yufa4ce792014-02-06 18:09:22 -0800314
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700315 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800316}
317
318void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700319ContactStorage::getEndorseList(const Name& identity, vector<string>& endorseList)
Yingdi Yufa4ce792014-02-06 18:09:22 -0800320{
321 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700322 sqlite3_prepare_v2(m_db,
323 "SELECT profile_type FROM ContactProfile \
324 WHERE profile_identity=? AND endorse=1 ORDER BY profile_type",
325 -1, &stmt, 0);
326 sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800327
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700328 while (sqlite3_step(stmt) == SQLITE_ROW) {
329 string profileType = sqlite3_column_string(stmt, 0);
330 endorseList.push_back(profileType);
331 }
332 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800333}
334
335
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700336void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800337ContactStorage::removeContact(const Name& identityName)
Yingdi Yuae8217c2013-11-09 00:03:26 -0800338{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700339 string identity = identityName.toUri();
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700340
341 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700342 sqlite3_prepare_v2(m_db, "DELETE FROM Contact WHERE contact_namespace=?", -1, &stmt, 0);
343 sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700344 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700345 sqlite3_finalize(stmt);
Yingdi Yuae8217c2013-11-09 00:03:26 -0800346
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700347 sqlite3_prepare_v2(m_db, "DELETE FROM ContactProfile WHERE profile_identity=?", -1, &stmt, 0);
348 sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700349 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700350 sqlite3_finalize(stmt);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700351
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700352 sqlite3_prepare_v2(m_db, "DELETE FROM TrustScope WHERE contact_namespace=?", -1, &stmt, 0);
353 sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700354 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700355 sqlite3_finalize(stmt);
Yingdi Yuae8217c2013-11-09 00:03:26 -0800356}
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700357
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700358void
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800359ContactStorage::addContact(const Contact& contact)
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700360{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700361 if (doesContactExist(contact.getNameSpace()))
Yingdi Yuf8f572d2014-01-13 11:19:47 -0800362 throw Error("Normal Contact has already existed");
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700363
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700364 string identity = contact.getNameSpace().toUri();
Yingdi Yu71c01872013-11-03 16:22:05 -0800365 bool isIntroducer = contact.isIntroducer();
366
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700367 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700368 sqlite3_prepare_v2(m_db,
369 "INSERT INTO Contact (contact_namespace, contact_alias, contact_keyName, \
370 contact_key, notBefore, notAfter, is_introducer) \
371 values (?, ?, ?, ?, ?, ?, ?)",
372 -1, &stmt, 0);
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700373
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700374 sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
375 sqlite3_bind_string(stmt, 2, contact.getAlias(), SQLITE_TRANSIENT);
376 sqlite3_bind_string(stmt, 3, contact.getPublicKeyName().toUri(), SQLITE_TRANSIENT);
377 sqlite3_bind_text(stmt, 4,
378 reinterpret_cast<const char*>(contact.getPublicKey().get().buf()),
379 contact.getPublicKey().get().size(), SQLITE_TRANSIENT);
Yingdi Yua7876722014-03-25 14:46:55 -0700380 sqlite3_bind_int64(stmt, 5, time::toUnixTimestamp(contact.getNotBefore()).count());
381 sqlite3_bind_int64(stmt, 6, time::toUnixTimestamp(contact.getNotAfter()).count());
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800382 sqlite3_bind_int(stmt, 7, (isIntroducer ? 1 : 0));
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700383
Yingdi Yu1cc45d92015-02-09 14:19:54 -0800384 sqlite3_step(stmt);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800385
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700386 sqlite3_finalize(stmt);
Yingdi Yu71c01872013-11-03 16:22:05 -0800387
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800388 const Profile& profile = contact.getProfile();
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700389 for (Profile::const_iterator it = profile.begin(); it != profile.end(); it++) {
390 sqlite3_prepare_v2(m_db,
391 "INSERT INTO ContactProfile \
392 (profile_identity, profile_type, profile_value, endorse) \
393 values (?, ?, ?, 0)",
394 -1, &stmt, 0);
395 sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
396 sqlite3_bind_string(stmt, 2, it->first, SQLITE_TRANSIENT);
397 sqlite3_bind_string(stmt, 3, it->second, SQLITE_TRANSIENT);
Yingdi Yu1cc45d92015-02-09 14:19:54 -0800398 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700399 sqlite3_finalize(stmt);
400 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800401
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700402 if (isIntroducer) {
403 Contact::const_iterator it = contact.trustScopeBegin();
404 Contact::const_iterator end = contact.trustScopeEnd();
405
406 while (it != end) {
407 sqlite3_prepare_v2(m_db,
408 "INSERT INTO TrustScope (contact_namespace, trust_scope) values (?, ?)",
409 -1, &stmt, 0);
410 sqlite3_bind_string(stmt, 1, identity, SQLITE_TRANSIENT);
411 sqlite3_bind_string(stmt, 2, it->first.toUri(), SQLITE_TRANSIENT);
Yingdi Yu1cc45d92015-02-09 14:19:54 -0800412 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700413 sqlite3_finalize(stmt);
414 it++;
Yingdi Yub2e747d2013-11-05 23:06:43 -0800415 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700416 }
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700417}
418
Yingdi Yufa4ce792014-02-06 18:09:22 -0800419
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800420shared_ptr<Contact>
421ContactStorage::getContact(const Name& identity) const
Yingdi Yufa4ce792014-02-06 18:09:22 -0800422{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800423 shared_ptr<Contact> contact;
424 Profile profile;
425
Yingdi Yufa4ce792014-02-06 18:09:22 -0800426 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700427 sqlite3_prepare_v2(m_db,
428 "SELECT contact_alias, contact_keyName, contact_key, notBefore, notAfter, \
429 is_introducer FROM Contact where contact_namespace=?",
430 -1, &stmt, 0);
431 sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800432
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700433 if (sqlite3_step(stmt) == SQLITE_ROW) {
434 string alias = sqlite3_column_string(stmt, 0);
435 string keyName = sqlite3_column_string(stmt, 1);
436 PublicKey key(sqlite3_column_text(stmt, 2), sqlite3_column_bytes (stmt, 2));
437 time::system_clock::TimePoint notBefore =
438 time::fromUnixTimestamp(time::milliseconds(sqlite3_column_int64 (stmt, 3)));
439 time::system_clock::TimePoint notAfter =
440 time::fromUnixTimestamp(time::milliseconds(sqlite3_column_int64 (stmt, 4)));
441 int isIntroducer = sqlite3_column_int (stmt, 5);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800442
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700443 contact = make_shared<Contact>(identity, alias, Name(keyName),
444 notBefore, notAfter, key, isIntroducer);
445 }
446 sqlite3_finalize(stmt);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800447
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700448 sqlite3_prepare_v2(m_db,
449 "SELECT profile_type, profile_value FROM ContactProfile \
450 where profile_identity=?",
451 -1, &stmt, 0);
452 sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700453
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700454 while (sqlite3_step(stmt) == SQLITE_ROW) {
455 string type = sqlite3_column_string(stmt, 0);
456 string value = sqlite3_column_string(stmt, 1);
457 profile[type] = value;
458 }
459 sqlite3_finalize(stmt);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800460 contact->setProfile(profile);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800461
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700462 if (contact->isIntroducer()) {
463 sqlite3_prepare_v2(m_db,
464 "SELECT trust_scope FROM TrustScope WHERE contact_namespace=?",
465 -1, &stmt, 0);
466 sqlite3_bind_string(stmt, 1, identity.toUri(), SQLITE_TRANSIENT);
Yingdi Yufa4ce792014-02-06 18:09:22 -0800467
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700468 while (sqlite3_step(stmt) == SQLITE_ROW) {
469 Name scope(sqlite3_column_string(stmt, 0));
470 contact->addTrustScope(scope);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800471 }
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700472 sqlite3_finalize(stmt);
473 }
Yingdi Yufa4ce792014-02-06 18:09:22 -0800474
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800475 return contact;
Yingdi Yufa4ce792014-02-06 18:09:22 -0800476}
477
478
Yingdi Yub2e747d2013-11-05 23:06:43 -0800479void
Yingdi Yufa4ce792014-02-06 18:09:22 -0800480ContactStorage::updateIsIntroducer(const Name& identity, bool isIntroducer)
Yingdi Yub2e747d2013-11-05 23:06:43 -0800481{
482 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700483 sqlite3_prepare_v2(m_db, "UPDATE Contact SET is_introducer=? WHERE contact_namespace=?",
484 -1, &stmt, 0);
Yingdi Yub2e747d2013-11-05 23:06:43 -0800485 sqlite3_bind_int(stmt, 1, (isIntroducer ? 1 : 0));
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700486 sqlite3_bind_string(stmt, 2, identity.toUri(), SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700487 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700488 sqlite3_finalize(stmt);
Yingdi Yub2e747d2013-11-05 23:06:43 -0800489 return;
490}
491
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700492void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700493ContactStorage::updateAlias(const Name& identity, const string& alias)
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700494{
Yingdi Yu71c01872013-11-03 16:22:05 -0800495 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700496 sqlite3_prepare_v2(m_db, "UPDATE Contact SET contact_alias=? WHERE contact_namespace=?",
497 -1, &stmt, 0);
498 sqlite3_bind_string(stmt, 1, alias, SQLITE_TRANSIENT);
499 sqlite3_bind_string(stmt, 2, identity.toUri(), SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700500 sqlite3_step(stmt);
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700501 sqlite3_finalize(stmt);
Yingdi Yu71c01872013-11-03 16:22:05 -0800502 return;
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700503}
504
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700505bool
Yingdi Yu71c01872013-11-03 16:22:05 -0800506ContactStorage::doesContactExist(const Name& name)
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700507{
508 bool result = false;
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700509
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700510 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700511 sqlite3_prepare_v2(m_db, "SELECT count(*) FROM Contact WHERE contact_namespace=?", -1, &stmt, 0);
512 sqlite3_bind_string(stmt, 1, name.toUri(), SQLITE_TRANSIENT);
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700513
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700514 int res = sqlite3_step(stmt);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700515
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700516 if (res == SQLITE_ROW) {
517 int countAll = sqlite3_column_int (stmt, 0);
518 if (countAll > 0)
519 result = true;
520 }
521
522 sqlite3_finalize(stmt);
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700523 return result;
524}
525
Yingdi Yu76dd8002013-12-24 11:16:32 +0800526void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700527ContactStorage::getAllContacts(vector<shared_ptr<Contact> >& contacts) const
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700528{
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700529 vector<Name> contactNames;
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800530
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700531 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700532 sqlite3_prepare_v2(m_db, "SELECT contact_namespace FROM Contact", -1, &stmt, 0);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700533
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700534 while (sqlite3_step(stmt) == SQLITE_ROW) {
535 string identity = sqlite3_column_string(stmt, 0);
536 contactNames.push_back(Name(identity));
537 }
538 sqlite3_finalize(stmt);
Yingdi Yu71c01872013-11-03 16:22:05 -0800539
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700540 for (vector<Name>::iterator it = contactNames.begin(); it != contactNames.end(); it++) {
541 shared_ptr<Contact> contact = getContact(*it);
542 if (static_cast<bool>(contact))
543 contacts.push_back(contact);
544 }
Yingdi Yud04ed1a2013-10-14 14:07:03 -0700545}
Yingdi Yu3b318c12013-10-15 17:54:00 -0700546
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800547void
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700548ContactStorage::updateDnsData(const Block& data, const string& name,
549 const string& type, const string& dataName)
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700550{
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800551 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700552 sqlite3_prepare_v2(m_db,
553 "INSERT OR REPLACE INTO DnsData (dns_name, dns_type, dns_value, data_name) \
554 VALUES (?, ?, ?, ?)",
555 -1, &stmt, 0);
556 sqlite3_bind_string(stmt, 1, name, SQLITE_TRANSIENT);
557 sqlite3_bind_string(stmt, 2, type, SQLITE_TRANSIENT);
558 sqlite3_bind_block(stmt, 3, data, SQLITE_TRANSIENT);
559 sqlite3_bind_string(stmt, 4, dataName, SQLITE_TRANSIENT);
Yingdi Yu42125862014-08-07 17:04:28 -0700560 sqlite3_step(stmt);
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800561
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800562 sqlite3_finalize(stmt);
563}
564
565shared_ptr<Data>
566ContactStorage::getDnsData(const Name& dataName)
567{
568 shared_ptr<Data> data;
569
570 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700571 sqlite3_prepare_v2(m_db, "SELECT dns_value FROM DnsData where data_name=?", -1, &stmt, 0);
572 sqlite3_bind_string(stmt, 1, dataName.toUri(), SQLITE_TRANSIENT);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700573
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700574 if (sqlite3_step(stmt) == SQLITE_ROW) {
575 data = make_shared<Data>();
576 data->wireDecode(sqlite3_column_block(stmt, 0));
577 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800578 sqlite3_finalize(stmt);
579
580 return data;
581}
582
583shared_ptr<Data>
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700584ContactStorage::getDnsData(const string& name, const string& type)
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800585{
586 shared_ptr<Data> data;
587
588 sqlite3_stmt *stmt;
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700589 sqlite3_prepare_v2(m_db, "SELECT dns_value FROM DnsData where dns_name=? and dns_type=?",
590 -1, &stmt, 0);
591 sqlite3_bind_string(stmt, 1, name, SQLITE_TRANSIENT);
592 sqlite3_bind_string(stmt, 2, type, SQLITE_TRANSIENT);
Yingdi Yufa0b6a02014-04-30 14:26:42 -0700593
Yingdi Yu0b0a7362014-08-05 16:31:30 -0700594 if (sqlite3_step(stmt) == SQLITE_ROW) {
595 data = make_shared<Data>();
596 data->wireDecode(sqlite3_column_block(stmt, 0));
597 }
Yingdi Yu348f5ea2014-03-01 14:47:25 -0800598 sqlite3_finalize(stmt);
599
600 return data;
601}
602
Yingdi Yueb692ac2015-02-10 18:46:18 -0800603} // namespace chronochat