From 975742531dce89ba77d6c337da16ca710bba8a66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Sat, 12 Mar 2011 13:37:23 +0100
Subject: Cache vcard photo hashes.


diff --git a/Swiften/VCards/VCardFileStorage.cpp b/Swiften/VCards/VCardFileStorage.cpp
index 63652ad..3f84678 100644
--- a/Swiften/VCards/VCardFileStorage.cpp
+++ b/Swiften/VCards/VCardFileStorage.cpp
@@ -7,8 +7,13 @@
 #include "Swiften/VCards/VCardFileStorage.h"
 
 #include <boost/filesystem/fstream.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
 
 #include <Swiften/Base/String.h>
+#include <Swiften/StringCodecs/Hexify.h>
+#include <Swiften/StringCodecs/SHA1.h>
+#include <Swiften/Base/foreach.h>
 #include "Swiften/JID/JID.h"
 #include "Swiften/Base/ByteArray.h"
 #include "Swiften/Elements/VCard.h"
@@ -19,6 +24,28 @@
 namespace Swift {
 
 VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir) {
+	cacheFile = vcardsPath / "vcards.xml";
+	if (boost::filesystem::exists(cacheFile)) {
+		boost::property_tree::ptree tree;
+		try {
+			boost::property_tree::xml_parser::read_xml(cacheFile.string(), tree);
+		}
+		catch (const boost::property_tree::xml_parser::xml_parser_error& e) {
+			std::cerr << "Error reading vcards file: " << e.filename() << ":" << e.line() << ": " << e.message() << std::endl;
+		}
+		foreach(const boost::property_tree::ptree::value_type &v, tree.get_child("vcards")) {
+			try {
+				JID jid(v.second.get<std::string>("jid"));
+				std::string hash(v.second.get<std::string>("phash"));
+				if (jid.isValid()) {
+					photoHashes.insert(std::make_pair(jid, hash));
+				}
+			}
+			catch (const boost::property_tree::ptree_error& e) {
+				std::cerr << "Invalid vcard value: " << e.what() << std::endl;
+			}
+		}
+	}
 }
 
 boost::shared_ptr<VCard> VCardFileStorage::getVCard(const JID& jid) const {
@@ -50,6 +77,7 @@ void VCardFileStorage::setVCard(const JID& jid, VCard::ref v) {
 	boost::filesystem::ofstream file(getVCardPath(jid));
 	file << VCardSerializer().serializePayload(v);
 	file.close();
+	getAndUpdatePhotoHash(jid, v);
 }
 
 boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const {
@@ -58,4 +86,48 @@ boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const {
 	return boost::filesystem::path(vcardsPath / (file + ".xml"));
 }
 
+std::string VCardFileStorage::getPhotoHash(const JID& jid) const {
+	PhotoHashMap::const_iterator i = photoHashes.find(jid);
+	if (i != photoHashes.end()) {
+		return i->second;
+	}
+	else {
+		VCard::ref vCard = getVCard(jid);
+		return getAndUpdatePhotoHash(jid, vCard);
+	}
+}
+
+std::string VCardFileStorage::getAndUpdatePhotoHash(const JID& jid, VCard::ref vCard) const {
+	std::string hash;
+	if (vCard && !vCard->getPhoto().isEmpty()) {
+		hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto()));
+	}
+	std::pair<PhotoHashMap::iterator, bool> r = photoHashes.insert(std::make_pair(jid, hash));
+	if (r.second) {
+		savePhotoHashes();
+	}
+	else if (r.first->second != hash) {
+		r.first->second = hash;
+		savePhotoHashes();
+	}
+	return hash;
+}
+
+void VCardFileStorage::savePhotoHashes() const {
+	boost::property_tree::ptree tree;
+	for (PhotoHashMap::const_iterator i = photoHashes.begin(); i != photoHashes.end(); ++i) {
+		boost::property_tree::ptree entry;
+		entry.put("jid", i->first.toString());
+		entry.put("phash", i->second);
+		tree.add_child("vcards.vcard", entry);
+	}
+	try {
+		boost::property_tree::xml_parser::write_xml(cacheFile.string(), tree);
+	}
+	catch (const boost::property_tree::xml_parser::xml_parser_error& e) {
+		std::cerr << "Error writing vcards file: " << e.filename() << ": " << e.message() << std::endl;
+	}
+}
+
+
 }
diff --git a/Swiften/VCards/VCardFileStorage.h b/Swiften/VCards/VCardFileStorage.h
index 5f8cb1a..26bf4b2 100644
--- a/Swiften/VCards/VCardFileStorage.h
+++ b/Swiften/VCards/VCardFileStorage.h
@@ -8,6 +8,8 @@
 
 #include <boost/shared_ptr.hpp>
 #include <boost/filesystem.hpp>
+#include <string>
+#include <map>
 
 #include "Swiften/VCards/VCardStorage.h"
 
@@ -19,10 +21,18 @@ namespace Swift {
 			virtual VCard::ref getVCard(const JID& jid) const;
 			virtual void setVCard(const JID& jid, VCard::ref v);
 
+			virtual std::string getPhotoHash(const JID&) const;
+
 		private:
 			boost::filesystem::path getVCardPath(const JID&) const;
 
+			std::string getAndUpdatePhotoHash(const JID& jid, VCard::ref vcard) const;
+			void savePhotoHashes() const;
+
 		private:
 			boost::filesystem::path vcardsPath;
+			boost::filesystem::path cacheFile;
+			typedef std::map<JID, std::string> PhotoHashMap;
+			mutable PhotoHashMap photoHashes;
 	};
 }
-- 
cgit v0.10.2-6-g49f6