From 0bebf1a69870f75432517cfcb6d115996cf5be4f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Mon, 22 Jun 2009 20:53:42 +0200
Subject: Send avatar vCard-updates in presence.


diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp
index 93b7c2a..6f1e02b 100644
--- a/Swift/Controllers/MainController.cpp
+++ b/Swift/Controllers/MainController.cpp
@@ -24,6 +24,7 @@
 #include "Swiften/Base/String.h"
 #include "Swiften/Client/Client.h"
 #include "Swiften/Elements/Presence.h"
+#include "Swiften/Elements/VCardUpdate.h"
 #include "Swiften/Roster/XMPPRoster.h"
 #include "Swiften/Queries/Responders/SoftwareVersionResponder.h"
 #include "Swiften/Roster/TreeWidgetFactory.h"
@@ -32,8 +33,20 @@
 #include "Swiften/Queries/Responders/DiscoInfoResponder.h"
 #include "Swiften/Disco/CapsInfoGenerator.h"
 #include "Swiften/Queries/Requests/GetDiscoInfoRequest.h"
+#include "Swiften/Queries/Requests/GetVCardRequest.h"
 #include "Swiften/Avatars/AvatarFileStorage.h"
 #include "Swiften/Avatars/AvatarManager.h"
+#include "Swiften/StringCodecs/SHA1.h"
+
+namespace {
+	void printIncomingData(const Swift::String& data) {
+		std::cout << "<- " << data << std::endl;
+	}
+
+	void printOutgoingData(const Swift::String& data) {
+		std::cout << "-> " << data << std::endl;
+	}
+}
 
 namespace Swift {
 
@@ -82,6 +95,8 @@ void MainController::handleConnected() {
 	delete presenceOracle_;
 	presenceOracle_ = new PresenceOracle(client_);
 
+	lastSentPresence_ = boost::shared_ptr<Presence>();
+
 	client_->onPresenceReceived.connect(boost::bind(&MainController::handleIncomingPresence, this, _1));
 
 	boost::shared_ptr<XMPPRoster> xmppRoster(new XMPPRoster());
@@ -118,11 +133,15 @@ void MainController::handleConnected() {
 	boost::shared_ptr<GetDiscoInfoRequest> discoInfoRequest(new GetDiscoInfoRequest(JID(), client_));
 	discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2));
 	discoInfoRequest->send();
+
+	boost::shared_ptr<GetVCardRequest> vCardRequest(new GetVCardRequest(JID(), client_));
+	vCardRequest->onResponse.connect(boost::bind(&MainController::handleOwnVCardReceived, this, _1, _2));
+	vCardRequest->send();
 	
 	//Send presence last to catch all the incoming presences.
 	boost::shared_ptr<Presence> initialPresence(new Presence());
 	initialPresence->addPayload(capsInfo_);
-	client_->sendPresence(initialPresence);
+	sendPresence(initialPresence);
 }
 
 void MainController::handleEventQueueLengthChange(int count) {
@@ -132,12 +151,22 @@ void MainController::handleEventQueueLengthChange(int count) {
 void MainController::handleChangeStatusRequest(StatusShow::Type show, const String &statusText) {
 	boost::shared_ptr<Presence> presence(new Presence());
 	presence->addPayload(capsInfo_);
-	presence->setShow(show);
-	presence->setStatus(statusText);
-	// FIXME: This is wrong. None doesn't mean unavailable
 	if (show == StatusShow::None) {
+		// FIXME: This is wrong. None doesn't mean unavailable
 		presence->setType(Presence::Unavailable);
 	}
+	else {
+		presence->setShow(show);
+	}
+	presence->setStatus(statusText);
+	sendPresence(presence);
+}
+
+void MainController::sendPresence(boost::shared_ptr<Presence> presence) {
+	if (!vCardPhotoHash_.isEmpty()) {
+		presence->addPayload(boost::shared_ptr<VCardUpdate>(new VCardUpdate(vCardPhotoHash_)));
+	}
+	lastSentPresence_ = presence;
 	client_->sendPresence(presence);
 	if (presence->getType() == Presence::Unavailable) {
 		logout();
@@ -156,7 +185,10 @@ void MainController::handleLoginRequest(const String &username, const String &pa
 	settings_->storeString("pass", remember ? password : "");
 
 	delete client_;
-	client_ = new Swift::Client(JID(username), password);
+	jid_ = JID(username);
+	client_ = new Swift::Client(jid_, password);
+	//client_->onDataRead.connect(&printIncomingData);
+	//client_->onDataWritten.connect(&printOutgoingData);
 	if (!certificateFile.isEmpty()) {
 		client_->setCertificate(certificateFile);
 	}
@@ -275,5 +307,14 @@ bool MainController::isMUC(const JID& jid) const {
   return mucControllers_.find(jid.toBare()) != mucControllers_.end();
 }
 
+void MainController::handleOwnVCardReceived(boost::shared_ptr<VCard> vCard, const boost::optional<Error>& error) {
+	if (!error && !vCard->getPhoto().isEmpty()) {
+		vCardPhotoHash_ = SHA1::getHexHash(vCard->getPhoto());
+		if (lastSentPresence_) {
+			sendPresence(lastSentPresence_);
+		}
+		avatarManager_->setAvatar(jid_, vCard->getPhoto());
+	}
+}
 
 }
diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h
index 650afd1..2b7c8b0 100644
--- a/Swift/Controllers/MainController.h
+++ b/Swift/Controllers/MainController.h
@@ -8,6 +8,7 @@
 #include "Swiften/Base/String.h"
 #include "Swiften/Client/ClientError.h"
 #include "Swiften/JID/JID.h"
+#include "Swiften/Elements/VCard.h"
 #include "Swiften/Elements/DiscoInfo.h"
 #include "Swiften/Elements/Error.h"
 #include "Swiften/Elements/Presence.h"
@@ -58,7 +59,9 @@ namespace Swift {
 			void handleError(const ClientError& error);
 			void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, const boost::optional<Error>&);
 			void handleEventQueueLengthChange(int count);
+			void handleOwnVCardReceived(boost::shared_ptr<VCard> vCard, const boost::optional<Error>& error);
 			ChatController* getChatController(const JID &contact);
+			void sendPresence(boost::shared_ptr<Presence> presence);
 			void logout();
 
 			virtual bool isMUC(const JID& muc) const;
@@ -84,9 +87,12 @@ namespace Swift {
 			std::map<JID, MUCController*> mucControllers_;
 			std::map<JID, ChatController*> chatControllers_;
 			boost::shared_ptr<DiscoInfo> serverDiscoInfo_;
+			JID jid_;
 			PresenceOracle* presenceOracle_;
 			SystemTrayController* systemTrayController_;
 			AvatarManager* avatarManager_;
+			boost::shared_ptr<Presence> lastSentPresence_;
+			String vCardPhotoHash_;
 	};
 }
 #endif
diff --git a/Swiften/Avatars/AvatarManager.cpp b/Swiften/Avatars/AvatarManager.cpp
index c15d002..6a1efc6 100644
--- a/Swiften/Avatars/AvatarManager.cpp
+++ b/Swiften/Avatars/AvatarManager.cpp
@@ -49,6 +49,12 @@ void AvatarManager::handleVCardReceived(const JID& from, const String& promisedH
 	setAvatarHash(from, realHash);
 }
 
+void AvatarManager::setAvatar(const JID& jid, const ByteArray& avatar) {
+	String hash = SHA1::getHexHash(avatar);
+	avatarStorage_->addAvatar(hash, avatar);
+	setAvatarHash(getAvatarJID(jid), hash);
+}
+
 void AvatarManager::setAvatarHash(const JID& from, const String& hash) {
 	avatarHashes_[from] = hash;
 	onAvatarChanged(from, hash);
diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h
index 13c6cb7..984ce19 100644
--- a/Swiften/Avatars/AvatarManager.h
+++ b/Swiften/Avatars/AvatarManager.h
@@ -23,6 +23,7 @@ namespace Swift {
 
 			String getAvatarHash(const JID&) const;
 			boost::filesystem::path getAvatarPath(const JID&) const;
+			void setAvatar(const JID&, const ByteArray& avatar);
 
 		public:
 			boost::signal<void (const JID&, const String&)> onAvatarChanged;
diff --git a/Swiften/Elements/VCardUpdate.h b/Swiften/Elements/VCardUpdate.h
index b6c8ebd..6bb79cc 100644
--- a/Swiften/Elements/VCardUpdate.h
+++ b/Swiften/Elements/VCardUpdate.h
@@ -6,7 +6,7 @@
 namespace Swift {
 	class VCardUpdate : public Payload {
 		public:
-			VCardUpdate() {}
+			VCardUpdate(const String& photoHash = "") : photoHash_(photoHash) {}
 
 			void setPhotoHash(const String& photoHash) { photoHash_ = photoHash; }
 			const String& getPhotoHash() { return photoHash_; }
-- 
cgit v0.10.2-6-g49f6