From 436ae921afbc5c2b461ee9b2d8fa9b1c869ed274 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Fri, 17 Jul 2009 09:03:16 +0200
Subject: Implement LinkLocalServiceInfo TXT record.


diff --git a/Nim/main.cpp b/Nim/main.cpp
index 607cc80..6747d4a 100644
--- a/Nim/main.cpp
+++ b/Nim/main.cpp
@@ -14,6 +14,7 @@
 #include "Swiften/EventLoop/SimpleEventLoop.h"
 #include "Swiften/EventLoop/EventOwner.h"
 #include "Swiften/Elements/Stanza.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
 #include "Swiften/LinkLocal/LinkLocalRoster.h"
 #include "Swiften/LinkLocal/DNSSDService.h"
 #include "Swiften/LinkLocal/AppleDNSSDService.h"
@@ -63,7 +64,16 @@ class Server {
 			if (!dnsSDServiceRegistered_) {
 				dnsSDServiceRegistered_ = true;
 				dnsSDService_->onServiceRegistered.connect(boost::bind(&Server::handleServiceRegistered, this, _1));
-				dnsSDService_->registerService(session->getJID().toBare().toString(), linkLocalConnectionPort_, std::map<String,String>());
+				LinkLocalServiceInfo info;
+				info.setFirstName("Remko");
+				info.setLastName("Tron\xc3\xe7on");
+				info.setEMail("email@example.com");
+				info.setJID(JID("jid@example.com"));
+				info.setMessage("I'm not Here");
+				info.setNick("remko");
+				info.setStatus(LinkLocalServiceInfo::Away);
+				info.setPort(linkLocalConnectionPort_);
+				dnsSDService_->registerService(session->getJID().toBare().toString(), linkLocalConnectionPort_, info);
 			}
 		}
 
diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h
index 88e3fae..bcc3756 100644
--- a/Swiften/Base/ByteArray.h
+++ b/Swiften/Base/ByteArray.h
@@ -55,6 +55,11 @@ namespace Swift {
 				return result;
 			}
 
+			ByteArray& operator+=(const ByteArray& b) {
+				data_.insert(data_.end(), b.data_.begin(), b.data_.end());
+				return *this;
+			}
+
 			friend bool operator==(const ByteArray& a, const ByteArray& b) {
 				return a.data_ == b.data_;
 			}
diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp
index 3b71f74..4dd74eb 100644
--- a/Swiften/LinkLocal/AppleDNSSDService.cpp
+++ b/Swiften/LinkLocal/AppleDNSSDService.cpp
@@ -6,6 +6,7 @@
 #include <sys/socket.h>
 
 #include "Swiften/EventLoop/MainEventLoop.h"
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
 
 namespace Swift {
 
@@ -44,12 +45,12 @@ void AppleDNSSDService::start() {
 	thread = new boost::thread(boost::bind(&AppleDNSSDService::doStart, shared_from_this()));
 }
 
-void AppleDNSSDService::registerService(const String& name, int port, const std::map<String,String>&) {
-	// TODO: Use properties
+void AppleDNSSDService::registerService(const String& name, int port, const LinkLocalServiceInfo& info) {
 	boost::lock_guard<boost::mutex> lock(sdRefsMutex);
 
 	assert(!registerSDRef);
-	DNSServiceErrorType result = DNSServiceRegister(&registerSDRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, 0, NULL, &AppleDNSSDService::handleServiceRegisteredGlobal, this);
+	ByteArray txtRecord = info.toTXTRecord();
+	DNSServiceErrorType result = DNSServiceRegister(&registerSDRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtRecord.getSize(), txtRecord.getData(), &AppleDNSSDService::handleServiceRegisteredGlobal, this);
 	interruptSelect();
 	if (result != kDNSServiceErr_NoError) {
 		onError();
diff --git a/Swiften/LinkLocal/AppleDNSSDService.h b/Swiften/LinkLocal/AppleDNSSDService.h
index 3607ce0..6299a96 100644
--- a/Swiften/LinkLocal/AppleDNSSDService.h
+++ b/Swiften/LinkLocal/AppleDNSSDService.h
@@ -14,7 +14,7 @@ namespace Swift {
 			AppleDNSSDService();
 			~AppleDNSSDService();
 
-			virtual void registerService(const String& name, int port, const std::map<String,String>& properties);
+			virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&);
 			virtual void unregisterService();
 			virtual void start();
 			virtual void stop();
diff --git a/Swiften/LinkLocal/DNSSDService.h b/Swiften/LinkLocal/DNSSDService.h
index 3437c58..214cad4 100644
--- a/Swiften/LinkLocal/DNSSDService.h
+++ b/Swiften/LinkLocal/DNSSDService.h
@@ -6,6 +6,8 @@
 #include "Swiften/Base/String.h"
 
 namespace Swift {
+	class LinkLocalServiceInfo;
+
 	class DNSSDService {
 		public:
 			struct Service {
@@ -18,7 +20,7 @@ namespace Swift {
 
 			virtual ~DNSSDService();
 
-			virtual void registerService(const String& name, int port, const std::map<String,String>& properties) = 0;
+			virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&) = 0;
 			virtual void unregisterService() = 0;
 			virtual void start() = 0;
 
diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp
new file mode 100644
index 0000000..99f83b8
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp
@@ -0,0 +1,48 @@
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace Swift {
+
+ByteArray LinkLocalServiceInfo::toTXTRecord() const {
+	ByteArray result(getEncoded("txtvers=1"));
+	if (!firstName.isEmpty()) {
+		result += getEncoded("1st=" + firstName);
+	}
+	if (!lastName.isEmpty()) {
+		result += getEncoded("last=" + lastName);
+	}
+	if (!email.isEmpty()) {
+		result += getEncoded("email=" + email);
+	}
+	if (jid.isValid()) {
+		result += getEncoded("jid=" + jid.toString());
+	}
+	if (!message.isEmpty()) {
+		result += getEncoded("msg=" + message);
+	}
+	if (!nick.isEmpty()) {
+		result += getEncoded("nick=" + nick);
+	}
+	if (port) {
+		result += getEncoded("port.p2pj=" + String(boost::lexical_cast<std::string>(*port)));
+	}
+
+	switch (status) {
+		case Available: result += getEncoded("status=avail"); break;
+		case Away: result += getEncoded("status=away"); break;
+		case DND: result += getEncoded("status=dnd"); break;
+	}
+
+	return result;
+}
+
+ByteArray LinkLocalServiceInfo::getEncoded(const String& s) {
+	ByteArray sizeByte;
+	sizeByte.resize(1);
+	assert(s.getLength() < 256);
+	sizeByte[0] = s.getUTF8Size();
+	return sizeByte + ByteArray(s);
+}
+
+}
diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.h b/Swiften/LinkLocal/LinkLocalServiceInfo.h
new file mode 100644
index 0000000..bd5286b
--- /dev/null
+++ b/Swiften/LinkLocal/LinkLocalServiceInfo.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <boost/optional.hpp>
+
+#include "Swiften/Base/ByteArray.h"
+#include "Swiften/Base/String.h"
+#include "Swiften/JID/JID.h"
+
+namespace Swift {
+
+	class LinkLocalServiceInfo {
+		public:
+			enum Status { Available, Away, DND };
+
+			LinkLocalServiceInfo() : status(Available) {}
+
+			const String& getFirstName() const { return firstName; }
+			void setFirstName(const String& f) { firstName = f; }
+
+			const String& getLastName() const { return lastName; }
+			void setLastName(const String& l) { lastName = l; }
+
+			const String& getEMail() const { return email; }
+			void setEMail(const String& e) { email = e; }
+
+			const JID& getJID() const { return jid; }
+			void setJID(const JID& j) { jid = j; }
+
+			const String& getMessage() const { return message; }
+			void setMessage(const String& m) { message = m; }
+
+			const String& getNick() const { return nick; }
+			void setNick(const String& n) { nick = n; }
+
+			Status getStatus() const { return status; }
+			void setStatus(Status s) { status = s; }
+
+			boost::optional<int> getPort() const { return port; }
+			void setPort(int p) { port = p; }
+
+			ByteArray toTXTRecord() const;
+
+		private:
+			static ByteArray getEncoded(const String&);
+
+		private:
+			String firstName;
+			String lastName;
+			String email;
+			JID jid;
+			String message;
+			String nick;
+			Status status;
+			boost::optional<int> port;
+	};
+}
diff --git a/Swiften/LinkLocal/Makefile.inc b/Swiften/LinkLocal/Makefile.inc
index 54315da..683447c 100644
--- a/Swiften/LinkLocal/Makefile.inc
+++ b/Swiften/LinkLocal/Makefile.inc
@@ -1,9 +1,12 @@
 SWIFTEN_SOURCES += \
 	Swiften/LinkLocal/DNSSDService.cpp \
-	Swiften/LinkLocal/LinkLocalRoster.cpp
+	Swiften/LinkLocal/LinkLocalRoster.cpp \
+	Swiften/LinkLocal/LinkLocalServiceInfo.cpp
 
 
 ifeq ($(MACOSX),1)
 SWIFTEN_SOURCES += \
 	Swiften/LinkLocal/AppleDNSSDService.cpp
 endif
+
+include Swiften/LinkLocal/UnitTest/Makefile.inc
diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
new file mode 100644
index 0000000..8efe4ae
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
@@ -0,0 +1,26 @@
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+
+#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"
+
+using namespace Swift;
+
+class LinkLocalServiceInfoTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(LinkLocalServiceInfoTest);
+		CPPUNIT_TEST(testGetTXTRecord);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		LinkLocalServiceInfoTest() {}
+
+		void testGetTXTRecord() {
+			LinkLocalServiceInfo info;
+			info.setFirstName("Remko");
+			info.setLastName("Tron\xc3\xe7on");
+			info.setStatus(LinkLocalServiceInfo::Away);
+
+			CPPUNIT_ASSERT_EQUAL(ByteArray("\x09txtvers=1\x09" + String("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away")), info.toTXTRecord());
+		}
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceInfoTest);
diff --git a/Swiften/LinkLocal/UnitTest/Makefile.inc b/Swiften/LinkLocal/UnitTest/Makefile.inc
new file mode 100644
index 0000000..abc1180
--- /dev/null
+++ b/Swiften/LinkLocal/UnitTest/Makefile.inc
@@ -0,0 +1,2 @@
+UNITTEST_SOURCES += \
+	Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp
-- 
cgit v0.10.2-6-g49f6