diff options
| author | Kevin Smith <git@kismith.co.uk> | 2009-07-31 18:38:11 (GMT) | 
|---|---|---|
| committer | Kevin Smith <git@kismith.co.uk> | 2009-07-31 18:38:11 (GMT) | 
| commit | 99b65c4dd72105755a7cf95297c9cf69dcbc6446 (patch) | |
| tree | c6c862f6ef33b2260c44c0229b29f65351223e7c | |
| parent | fed11bbc3bffd383e097ea63bb92442ce2daf6ed (diff) | |
| parent | aa60aa80d2d170a536c246ef6c221f92de7dd8ed (diff) | |
| download | swift-99b65c4dd72105755a7cf95297c9cf69dcbc6446.zip swift-99b65c4dd72105755a7cf95297c9cf69dcbc6446.tar.bz2 | |
Merge commit 'origin/master' into roster
94 files changed, 2680 insertions, 3722 deletions
| @@ -1,5 +1,6 @@  .DS_Store  *.dep +*.gcov  *.gcda  *.gcno  *.app diff --git a/3rdParty/Boost/Makefile.inc b/3rdParty/Boost/Makefile.inc index 27aed09..d28bbcb 100644 --- a/3rdParty/Boost/Makefile.inc +++ b/3rdParty/Boost/Makefile.inc @@ -57,6 +57,3 @@ endif  BOOST_OBJECTS = \  	$(BOOST_SOURCES:.cpp=.o) - -CLEANFILES += \ -	$(BOOST_OBJECTS) diff --git a/3rdParty/CppUnit/Makefile.inc b/3rdParty/CppUnit/Makefile.inc index 27aadc2..3749144 100644 --- a/3rdParty/CppUnit/Makefile.inc +++ b/3rdParty/CppUnit/Makefile.inc @@ -39,9 +39,5 @@ CPPUNIT_SOURCES = \  CPPUNIT_OBJECTS = \  	$(CPPUNIT_SOURCES:.cpp=.o) -CLEANFILES += \ -	$(CPPUNIT_OBJECTS) \ -	$(CPPUNIT_TARGET) -  $(CPPUNIT_TARGET): $(CPPUNIT_OBJECTS)  	$(QUIET_AR)$(AR) $(ARFLAGS) $@ $(CPPUNIT_OBJECTS) diff --git a/3rdParty/Expat/Makefile.inc b/3rdParty/Expat/Makefile.inc index c143263..a241cf1 100644 --- a/3rdParty/Expat/Makefile.inc +++ b/3rdParty/Expat/Makefile.inc @@ -8,10 +8,6 @@ EXPAT_SOURCES = \  EXPAT_OBJECTS = \  	$(EXPAT_SOURCES:.c=.o) -CLEANFILES += \ -	$(EXPAT_OBJECTS) \ -	$(EXPAT_TARGET) -  $(EXPAT_TARGET): $(EXPAT_OBJECTS)  	$(QUIET_AR)$(AR) $(ARFLAGS) $@ $(EXPAT_OBJECTS) diff --git a/3rdParty/LibIDN/Makefile.inc b/3rdParty/LibIDN/Makefile.inc index f0f64ac..2aeb34b 100644 --- a/3rdParty/LibIDN/Makefile.inc +++ b/3rdParty/LibIDN/Makefile.inc @@ -18,8 +18,3 @@ LIBIDN_SOURCES += \  LIBIDN_OBJECTS = \  	$(LIBIDN_SOURCES:.c=.o) - -CLEANFILES += \ -	$(LIBIDN_OBJECTS) - - diff --git a/3rdParty/SQLite/Makefile.inc b/3rdParty/SQLite/Makefile.inc index 339e7a0..141cfca 100644 --- a/3rdParty/SQLite/Makefile.inc +++ b/3rdParty/SQLite/Makefile.inc @@ -5,7 +5,3 @@ SQLITE_SOURCES = \  SQLITE_OBJECTS = \  	$(SQLITE_SOURCES:.c=.o) - -CLEANFILES += \ -	$(SQLITE_OBJECTS) \ -	$(SQLITE_TARGET) diff --git a/3rdParty/ZLib/Makefile.inc b/3rdParty/ZLib/Makefile.inc index dccfcf4..a30f65d 100644 --- a/3rdParty/ZLib/Makefile.inc +++ b/3rdParty/ZLib/Makefile.inc @@ -17,6 +17,3 @@ ZLIB_SOURCES += \  ZLIB_OBJECTS = \  	$(ZLIB_SOURCES:.c=.o) - -CLEANFILES += \ -	$(ZLIB_OBJECTS) diff --git a/Limber/Makefile.inc b/Limber/Makefile.inc index ea0d288..fe0e7d2 100644 --- a/Limber/Makefile.inc +++ b/Limber/Makefile.inc @@ -11,6 +11,5 @@ $(LIMBER_TARGET): $(SWIFTEN_TARGET) $(LIMBER_OBJECTS)  	$(QUIET_LINK)$(CXX) -o $(LIMBER_TARGET) $(LIMBER_OBJECTS) $(LDFLAGS) $(SWIFTEN_TARGET) $(LIBS)  #TARGETS += $(LIMBER_TARGET) -CLEANFILES += $(LIMBER_OBJECTS)  DEPS += \  	$(LIMBER_SOURCES:.cpp=.dep) \ @@ -1,7 +1,7 @@  include Makefile.config -CXXFLAGS += -I. -CFLAGS += -I. +CXXFLAGS += -I$(PWD) +CFLAGS += -I$(PWD)  ARFLAGS = rcs  .DEFAULT_GOAL = all @@ -66,16 +66,9 @@ coverage:  	tools/coverage/GenerateCoverageResults.sh  .PHONY: clean -clean: clean-deps $(CLEAN_TARGETS) - -	-$(RM) $(CLEANFILES) *.gcov -	-find . -name "*.gcda" -exec rm {} \; -	-find . -name "*.gcno" -exec rm {} \; - -.PHONY: clean-deps -clean-deps: -		-$(RM) $(DEPS) - +clean: $(CLEAN_TARGETS) +	-rm -rf $(CLEANFILES) +	-find . \( -name "*.dep" -or -name "*.a" -or -name "*.o" -or -name "*.obj" -or -name "*.gcda" -or -name "*.gcno" -or -name "*.gcov" \) -exec rm {} \;  ################################################################################  # Automatic dependency detection diff --git a/Makefile.config.in b/Makefile.config.in index 848f223..010075a 100644 --- a/Makefile.config.in +++ b/Makefile.config.in @@ -22,6 +22,7 @@ HAVE_EXPAT=@HAVE_EXPAT@  USE_BUNDLED_EXPAT=@USE_BUNDLED_EXPAT@  HAVE_LIBXML=@CONFIG_HAVE_LIBXML@  HAVE_OPENSSL=@CONFIG_HAVE_OPENSSL@ +HAVE_BONJOUR=@HAVE_BONJOUR@  HAVE_AVAHI=@HAVE_AVAHI@  WIN32=@CONFIG_WIN32@  MACOSX=@CONFIG_MACOSX@ diff --git a/QA/UnitTest/Makefile.inc b/QA/UnitTest/Makefile.inc index 531f616..f51828e 100644 --- a/QA/UnitTest/Makefile.inc +++ b/QA/UnitTest/Makefile.inc @@ -6,7 +6,7 @@ UNITTEST_OBJECTS = \  TEST_TARGETS += check -CLEANFILES += $(UNITTEST_OBJECTS) $(UNITTEST_TARGET) +CLEANFILES += $(UNITTEST_TARGET)  DEPS += $(UNITTEST_SOURCES:.cpp=.dep)  .PHONY: check diff --git a/QA/UnitTest/template/FooTest.cpp b/QA/UnitTest/template/FooTest.cpp index b6b9abf..9657360 100644 --- a/QA/UnitTest/template/FooTest.cpp +++ b/QA/UnitTest/template/FooTest.cpp @@ -9,8 +9,6 @@ class FooTest : public CppUnit::TestFixture {  		CPPUNIT_TEST_SUITE_END();  	public: -		FooTest() {} -  		void setUp() {  		} diff --git a/Slimber/CLI/Makefile.inc b/Slimber/CLI/Makefile.inc index 601929c..974b835 100644 --- a/Slimber/CLI/Makefile.inc +++ b/Slimber/CLI/Makefile.inc @@ -7,10 +7,9 @@ SLIMBER_CLI_OBJECTS = \  $(SLIMBER_CLI_TARGET): $(SWIFTEN_TARGET) $(SLIMBER_TARGET) $(SLIMBER_CLI_OBJECTS)  	$(QUIET_LINK)$(CXX) -o $(SLIMBER_CLI_TARGET) $(SLIMBER_CLI_OBJECTS) $(LDFLAGS) $(SLIMBER_TARGET) $(SWIFTEN_TARGET) $(LIBS) -TARGETS += $(SLIMBER_CLI_TARGET) +#TARGETS += $(SLIMBER_CLI_TARGET)  SLIMBER_TARGETS += $(SLIMBER_CLI_TARGET)  CLEANFILES += \ -	$(SLIMBER_CLI_OBJECTS) \  	$(SLIMBER_CLI_TARGET)  DEPS += \  	$(SLIMBER_CLI_SOURCES:.cpp=.dep) \ diff --git a/Slimber/CLI/main.cpp b/Slimber/CLI/main.cpp index 40f41c8..b82ffcd 100644 --- a/Slimber/CLI/main.cpp +++ b/Slimber/CLI/main.cpp @@ -2,14 +2,12 @@  #include <boost/bind.hpp>  #include "Swiften/Base/Platform.h" -#if defined(SWIFTEN_PLATFORM_MACOSX) || defined(SWIFTEN_PLATFORM_WINDOWS) -#include "Swiften/LinkLocal/AppleDNSSDService.h" -#else -#include "Swiften/LinkLocal/AvahiDNSSDService.h" -#endif  #include "Slimber/Server.h"  #include "Slimber/FileVCardCollection.h" -#include "Swiften/LinkLocal/LinkLocalRoster.h" +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h"  #include "Swiften/EventLoop/SimpleEventLoop.h"  #include "Swiften/Application/Platform/PlatformApplication.h" @@ -17,21 +15,16 @@ using namespace Swift;  int main() {  	SimpleEventLoop eventLoop; +	boost::shared_ptr<BonjourQuerier> querier(new BonjourQuerier()); +	querier->start(); +	LinkLocalServiceBrowser browser(querier); +	browser.start(); -	boost::shared_ptr<DNSSDService> dnsSDService; -#if defined(SWIFTEN_PLATFORM_MACOSX) || defined(SWIFTEN_PLATFORM_WINDOWS) -	dnsSDService = boost::shared_ptr<AppleDNSSDService>( -			new AppleDNSSDService()); -#else -	dnsSDService = boost::shared_ptr<AvahiDNSSDService>( -			new AvahiDNSSDService()); -#endif - -	boost::shared_ptr<LinkLocalRoster> linkLocalRoster = boost::shared_ptr<LinkLocalRoster>(new LinkLocalRoster(dnsSDService)); - +/*  	FileVCardCollection vCardCollection(PlatformApplication("Slimber").getSettingsDir()); -  	Server server(5222, 5562, linkLocalRoster, dnsSDService, &vCardCollection); +	*/ +	  	eventLoop.run();  	return 0;  } diff --git a/Slimber/Cocoa/Info.plist b/Slimber/Cocoa/Info.plist index bcbed49..f934a10 100644 --- a/Slimber/Cocoa/Info.plist +++ b/Slimber/Cocoa/Info.plist @@ -24,5 +24,7 @@  	<string>NSApplication</string>    <key>LSUIElement</key>    <string>1</string> +	<key>NSHumanReadableCopyright</key> +	<string>© 2009 Swift Development Team. All Rights Reserved.</string>  </dict>  </plist> diff --git a/Slimber/Cocoa/MainMenu.xib b/Slimber/Cocoa/MainMenu.xib index a5eb7e1..50e4ca3 100644 --- a/Slimber/Cocoa/MainMenu.xib +++ b/Slimber/Cocoa/MainMenu.xib @@ -8,7 +8,7 @@  		<string key="IBDocument.HIToolboxVersion">353.00</string>  		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">  			<bool key="EncodedWithXMLCoder">YES</bool> -			<integer value="205"/> +			<integer value="136"/>  		</object>  		<object class="NSArray" key="IBDocument.PluginDependencies">  			<bool key="EncodedWithXMLCoder">YES</bool> @@ -41,7 +41,7 @@  					<bool key="EncodedWithXMLCoder">YES</bool>  					<object class="NSMenuItem" id="694149608">  						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">NewApplication</string> +						<string key="NSTitle">Slimber</string>  						<string key="NSKeyEquiv"/>  						<int key="NSKeyEquivModMask">1048576</int>  						<int key="NSMnemonicLoc">2147483647</int> @@ -55,12 +55,12 @@  						</object>  						<string key="NSAction">submenuAction:</string>  						<object class="NSMenu" key="NSSubmenu" id="110575045"> -							<string key="NSTitle">NewApplication</string> +							<string key="NSTitle">Slimber</string>  							<object class="NSMutableArray" key="NSMenuItems">  								<bool key="EncodedWithXMLCoder">YES</bool>  								<object class="NSMenuItem" id="238522557">  									<reference key="NSMenu" ref="110575045"/> -									<string key="NSTitle">About NewApplication</string> +									<string key="NSTitle">About Slimber</string>  									<string key="NSKeyEquiv"/>  									<int key="NSMnemonicLoc">2147483647</int>  									<reference key="NSOnImage" ref="35465992"/> @@ -127,7 +127,7 @@  								</object>  								<object class="NSMenuItem" id="755159360">  									<reference key="NSMenu" ref="110575045"/> -									<string key="NSTitle">Hide NewApplication</string> +									<string key="NSTitle">Hide Slimber</string>  									<string key="NSKeyEquiv">h</string>  									<int key="NSKeyEquivModMask">1048576</int>  									<int key="NSMnemonicLoc">2147483647</int> @@ -165,7 +165,7 @@  								</object>  								<object class="NSMenuItem" id="632727374">  									<reference key="NSMenu" ref="110575045"/> -									<string key="NSTitle">Quit NewApplication</string> +									<string key="NSTitle">Quit Slimber</string>  									<string key="NSKeyEquiv">q</string>  									<int key="NSKeyEquivModMask">1048576</int>  									<int key="NSMnemonicLoc">2147483647</int> @@ -176,943 +176,9 @@  							<string key="NSName">_NSAppleMenu</string>  						</object>  					</object> -					<object class="NSMenuItem" id="379814623"> -						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">File</string> -						<string key="NSKeyEquiv"/> -						<int key="NSKeyEquivModMask">1048576</int> -						<int key="NSMnemonicLoc">2147483647</int> -						<reference key="NSOnImage" ref="35465992"/> -						<reference key="NSMixedImage" ref="502551668"/> -						<string key="NSAction">submenuAction:</string> -						<object class="NSMenu" key="NSSubmenu" id="720053764"> -							<string key="NSTitle">File</string> -							<object class="NSMutableArray" key="NSMenuItems"> -								<bool key="EncodedWithXMLCoder">YES</bool> -								<object class="NSMenuItem" id="705341025"> -									<reference key="NSMenu" ref="720053764"/> -									<string key="NSTitle">New</string> -									<string key="NSKeyEquiv">n</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="722745758"> -									<reference key="NSMenu" ref="720053764"/> -									<string type="base64-UTF8" key="NSTitle">T3BlbuKApg</string> -									<string key="NSKeyEquiv">o</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="1025936716"> -									<reference key="NSMenu" ref="720053764"/> -									<string key="NSTitle">Open Recent</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="1065607017"> -										<string key="NSTitle">Open Recent</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="759406840"> -												<reference key="NSMenu" ref="1065607017"/> -												<string key="NSTitle">Clear Menu</string> -												<string key="NSKeyEquiv"/> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -										</object> -										<string key="NSName">_NSRecentDocumentsMenu</string> -									</object> -								</object> -								<object class="NSMenuItem" id="425164168"> -									<reference key="NSMenu" ref="720053764"/> -									<bool key="NSIsDisabled">YES</bool> -									<bool key="NSIsSeparator">YES</bool> -									<string key="NSTitle"/> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="776162233"> -									<reference key="NSMenu" ref="720053764"/> -									<string key="NSTitle">Close</string> -									<string key="NSKeyEquiv">w</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="1023925487"> -									<reference key="NSMenu" ref="720053764"/> -									<string key="NSTitle">Save</string> -									<string key="NSKeyEquiv">s</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="117038363"> -									<reference key="NSMenu" ref="720053764"/> -									<string type="base64-UTF8" key="NSTitle">U2F2ZSBBc+KApg</string> -									<string key="NSKeyEquiv">S</string> -									<int key="NSKeyEquivModMask">1179648</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="579971712"> -									<reference key="NSMenu" ref="720053764"/> -									<string key="NSTitle">Revert to Saved</string> -									<string key="NSKeyEquiv"/> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="1010469920"> -									<reference key="NSMenu" ref="720053764"/> -									<bool key="NSIsDisabled">YES</bool> -									<bool key="NSIsSeparator">YES</bool> -									<string key="NSTitle"/> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="294629803"> -									<reference key="NSMenu" ref="720053764"/> -									<string key="NSTitle">Page Setup...</string> -									<string key="NSKeyEquiv">P</string> -									<int key="NSKeyEquivModMask">1179648</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSToolTip"/> -								</object> -								<object class="NSMenuItem" id="49223823"> -									<reference key="NSMenu" ref="720053764"/> -									<string type="base64-UTF8" key="NSTitle">UHJpbnTigKY</string> -									<string key="NSKeyEquiv">p</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -							</object> -						</object> -					</object> -					<object class="NSMenuItem" id="952259628"> -						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">Edit</string> -						<string key="NSKeyEquiv"/> -						<int key="NSKeyEquivModMask">1048576</int> -						<int key="NSMnemonicLoc">2147483647</int> -						<reference key="NSOnImage" ref="35465992"/> -						<reference key="NSMixedImage" ref="502551668"/> -						<string key="NSAction">submenuAction:</string> -						<object class="NSMenu" key="NSSubmenu" id="789758025"> -							<string key="NSTitle">Edit</string> -							<object class="NSMutableArray" key="NSMenuItems"> -								<bool key="EncodedWithXMLCoder">YES</bool> -								<object class="NSMenuItem" id="1058277027"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Undo</string> -									<string key="NSKeyEquiv">z</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="790794224"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Redo</string> -									<string key="NSKeyEquiv">Z</string> -									<int key="NSKeyEquivModMask">1179648</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="1040322652"> -									<reference key="NSMenu" ref="789758025"/> -									<bool key="NSIsDisabled">YES</bool> -									<bool key="NSIsSeparator">YES</bool> -									<string key="NSTitle"/> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="296257095"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Cut</string> -									<string key="NSKeyEquiv">x</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="860595796"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Copy</string> -									<string key="NSKeyEquiv">c</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="29853731"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Paste</string> -									<string key="NSKeyEquiv">v</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="437104165"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Delete</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="583158037"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Select All</string> -									<string key="NSKeyEquiv">a</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="212016141"> -									<reference key="NSMenu" ref="789758025"/> -									<bool key="NSIsDisabled">YES</bool> -									<bool key="NSIsSeparator">YES</bool> -									<string key="NSTitle"/> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="892235320"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Find</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="963351320"> -										<string key="NSTitle">Find</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="447796847"> -												<reference key="NSMenu" ref="963351320"/> -												<string type="base64-UTF8" key="NSTitle">RmluZOKApg</string> -												<string key="NSKeyEquiv">f</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">1</int> -											</object> -											<object class="NSMenuItem" id="326711663"> -												<reference key="NSMenu" ref="963351320"/> -												<string key="NSTitle">Find Next</string> -												<string key="NSKeyEquiv">g</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">2</int> -											</object> -											<object class="NSMenuItem" id="270902937"> -												<reference key="NSMenu" ref="963351320"/> -												<string key="NSTitle">Find Previous</string> -												<string key="NSKeyEquiv">G</string> -												<int key="NSKeyEquivModMask">1179648</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">3</int> -											</object> -											<object class="NSMenuItem" id="159080638"> -												<reference key="NSMenu" ref="963351320"/> -												<string key="NSTitle">Use Selection for Find</string> -												<string key="NSKeyEquiv">e</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">7</int> -											</object> -											<object class="NSMenuItem" id="88285865"> -												<reference key="NSMenu" ref="963351320"/> -												<string key="NSTitle">Jump to Selection</string> -												<string key="NSKeyEquiv">j</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -										</object> -									</object> -								</object> -								<object class="NSMenuItem" id="972420730"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Spelling and Grammar</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="769623530"> -										<string key="NSTitle">Spelling and Grammar</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="679648819"> -												<reference key="NSMenu" ref="769623530"/> -												<string type="base64-UTF8" key="NSTitle">U2hvdyBTcGVsbGluZ+KApg</string> -												<string key="NSKeyEquiv">:</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="96193923"> -												<reference key="NSMenu" ref="769623530"/> -												<string key="NSTitle">Check Spelling</string> -												<string key="NSKeyEquiv">;</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="948374510"> -												<reference key="NSMenu" ref="769623530"/> -												<string key="NSTitle">Check Spelling While Typing</string> -												<string key="NSKeyEquiv"/> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="967646866"> -												<reference key="NSMenu" ref="769623530"/> -												<string key="NSTitle">Check Grammar With Spelling</string> -												<string key="NSKeyEquiv"/> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -										</object> -									</object> -								</object> -								<object class="NSMenuItem" id="507821607"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Substitutions</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="698887838"> -										<string key="NSTitle">Substitutions</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="605118523"> -												<reference key="NSMenu" ref="698887838"/> -												<string key="NSTitle">Smart Copy/Paste</string> -												<string key="NSKeyEquiv">f</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">1</int> -											</object> -											<object class="NSMenuItem" id="197661976"> -												<reference key="NSMenu" ref="698887838"/> -												<string key="NSTitle">Smart Quotes</string> -												<string key="NSKeyEquiv">g</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">2</int> -											</object> -											<object class="NSMenuItem" id="708854459"> -												<reference key="NSMenu" ref="698887838"/> -												<string key="NSTitle">Smart Links</string> -												<string key="NSKeyEquiv">G</string> -												<int key="NSKeyEquivModMask">1179648</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">3</int> -											</object> -										</object> -									</object> -								</object> -								<object class="NSMenuItem" id="676164635"> -									<reference key="NSMenu" ref="789758025"/> -									<string key="NSTitle">Speech</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="785027613"> -										<string key="NSTitle">Speech</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="731782645"> -												<reference key="NSMenu" ref="785027613"/> -												<string key="NSTitle">Start Speaking</string> -												<string key="NSKeyEquiv"/> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="680220178"> -												<reference key="NSMenu" ref="785027613"/> -												<string key="NSTitle">Stop Speaking</string> -												<string key="NSKeyEquiv"/> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -										</object> -									</object> -								</object> -							</object> -						</object> -					</object> -					<object class="NSMenuItem" id="302598603"> -						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">Format</string> -						<string key="NSKeyEquiv"/> -						<int key="NSMnemonicLoc">2147483647</int> -						<reference key="NSOnImage" ref="35465992"/> -						<reference key="NSMixedImage" ref="502551668"/> -						<string key="NSAction">submenuAction:</string> -						<object class="NSMenu" key="NSSubmenu" id="941447902"> -							<string key="NSTitle">Format</string> -							<object class="NSMutableArray" key="NSMenuItems"> -								<bool key="EncodedWithXMLCoder">YES</bool> -								<object class="NSMenuItem" id="792887677"> -									<reference key="NSMenu" ref="941447902"/> -									<string key="NSTitle">Font</string> -									<string key="NSKeyEquiv"/> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="786677654"> -										<string key="NSTitle">Font</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="159677712"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Show Fonts</string> -												<string key="NSKeyEquiv">t</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="305399458"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Bold</string> -												<string key="NSKeyEquiv">b</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">2</int> -											</object> -											<object class="NSMenuItem" id="814362025"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Italic</string> -												<string key="NSKeyEquiv">i</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">1</int> -											</object> -											<object class="NSMenuItem" id="330926929"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Underline</string> -												<string key="NSKeyEquiv">u</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="533507878"> -												<reference key="NSMenu" ref="786677654"/> -												<bool key="NSIsDisabled">YES</bool> -												<bool key="NSIsSeparator">YES</bool> -												<string key="NSTitle"/> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="158063935"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Bigger</string> -												<string key="NSKeyEquiv">+</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">3</int> -											</object> -											<object class="NSMenuItem" id="885547335"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Smaller</string> -												<string key="NSKeyEquiv">-</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<int key="NSTag">4</int> -											</object> -											<object class="NSMenuItem" id="901062459"> -												<reference key="NSMenu" ref="786677654"/> -												<bool key="NSIsDisabled">YES</bool> -												<bool key="NSIsSeparator">YES</bool> -												<string key="NSTitle"/> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="767671776"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Kern</string> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<string key="NSAction">submenuAction:</string> -												<object class="NSMenu" key="NSSubmenu" id="175441468"> -													<string key="NSTitle">Kern</string> -													<object class="NSMutableArray" key="NSMenuItems"> -														<bool key="EncodedWithXMLCoder">YES</bool> -														<object class="NSMenuItem" id="252969304"> -															<reference key="NSMenu" ref="175441468"/> -															<string key="NSTitle">Use Default</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="766922938"> -															<reference key="NSMenu" ref="175441468"/> -															<string key="NSTitle">Use None</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="677519740"> -															<reference key="NSMenu" ref="175441468"/> -															<string key="NSTitle">Tighten</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="238351151"> -															<reference key="NSMenu" ref="175441468"/> -															<string key="NSTitle">Loosen</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -													</object> -												</object> -											</object> -											<object class="NSMenuItem" id="691570813"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Ligature</string> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<string key="NSAction">submenuAction:</string> -												<object class="NSMenu" key="NSSubmenu" id="1058217995"> -													<string key="NSTitle">Ligature</string> -													<object class="NSMutableArray" key="NSMenuItems"> -														<bool key="EncodedWithXMLCoder">YES</bool> -														<object class="NSMenuItem" id="706297211"> -															<reference key="NSMenu" ref="1058217995"/> -															<string key="NSTitle">Use Default</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="568384683"> -															<reference key="NSMenu" ref="1058217995"/> -															<string key="NSTitle">Use None</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="663508465"> -															<reference key="NSMenu" ref="1058217995"/> -															<string key="NSTitle">Use All</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -													</object> -												</object> -											</object> -											<object class="NSMenuItem" id="769124883"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Baseline</string> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -												<string key="NSAction">submenuAction:</string> -												<object class="NSMenu" key="NSSubmenu" id="18263474"> -													<string key="NSTitle">Baseline</string> -													<object class="NSMutableArray" key="NSMenuItems"> -														<bool key="EncodedWithXMLCoder">YES</bool> -														<object class="NSMenuItem" id="257962622"> -															<reference key="NSMenu" ref="18263474"/> -															<string key="NSTitle">Use Default</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="644725453"> -															<reference key="NSMenu" ref="18263474"/> -															<string key="NSTitle">Superscript</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="1037576581"> -															<reference key="NSMenu" ref="18263474"/> -															<string key="NSTitle">Subscript</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="941806246"> -															<reference key="NSMenu" ref="18263474"/> -															<string key="NSTitle">Raise</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -														<object class="NSMenuItem" id="1045724900"> -															<reference key="NSMenu" ref="18263474"/> -															<string key="NSTitle">Lower</string> -															<string key="NSKeyEquiv"/> -															<int key="NSMnemonicLoc">2147483647</int> -															<reference key="NSOnImage" ref="35465992"/> -															<reference key="NSMixedImage" ref="502551668"/> -														</object> -													</object> -												</object> -											</object> -											<object class="NSMenuItem" id="739652853"> -												<reference key="NSMenu" ref="786677654"/> -												<bool key="NSIsDisabled">YES</bool> -												<bool key="NSIsSeparator">YES</bool> -												<string key="NSTitle"/> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="1012600125"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Show Colors</string> -												<string key="NSKeyEquiv">C</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="214559597"> -												<reference key="NSMenu" ref="786677654"/> -												<bool key="NSIsDisabled">YES</bool> -												<bool key="NSIsSeparator">YES</bool> -												<string key="NSTitle"/> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="596732606"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Copy Style</string> -												<string key="NSKeyEquiv">c</string> -												<int key="NSKeyEquivModMask">1572864</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="393423671"> -												<reference key="NSMenu" ref="786677654"/> -												<string key="NSTitle">Paste Style</string> -												<string key="NSKeyEquiv">v</string> -												<int key="NSKeyEquivModMask">1572864</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -										</object> -										<string key="NSName">_NSFontMenu</string> -									</object> -								</object> -								<object class="NSMenuItem" id="15516124"> -									<reference key="NSMenu" ref="941447902"/> -									<string key="NSTitle">Text</string> -									<string key="NSKeyEquiv"/> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -									<string key="NSAction">submenuAction:</string> -									<object class="NSMenu" key="NSSubmenu" id="23081656"> -										<string key="NSTitle">Text</string> -										<object class="NSMutableArray" key="NSMenuItems"> -											<bool key="EncodedWithXMLCoder">YES</bool> -											<object class="NSMenuItem" id="135107054"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Align Left</string> -												<string key="NSKeyEquiv">{</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="310547522"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Center</string> -												<string key="NSKeyEquiv">|</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="436088763"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Justify</string> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="498119243"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Align Right</string> -												<string key="NSKeyEquiv">}</string> -												<int key="NSKeyEquivModMask">1048576</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="607995063"> -												<reference key="NSMenu" ref="23081656"/> -												<bool key="NSIsDisabled">YES</bool> -												<bool key="NSIsSeparator">YES</bool> -												<string key="NSTitle"/> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="420564933"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Show Ruler</string> -												<string key="NSKeyEquiv"/> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="479856769"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Copy Ruler</string> -												<string key="NSKeyEquiv">c</string> -												<int key="NSKeyEquivModMask">1310720</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -											<object class="NSMenuItem" id="333628178"> -												<reference key="NSMenu" ref="23081656"/> -												<string key="NSTitle">Paste Ruler</string> -												<string key="NSKeyEquiv">v</string> -												<int key="NSKeyEquivModMask">1310720</int> -												<int key="NSMnemonicLoc">2147483647</int> -												<reference key="NSOnImage" ref="35465992"/> -												<reference key="NSMixedImage" ref="502551668"/> -											</object> -										</object> -									</object> -								</object> -							</object> -						</object> -					</object> -					<object class="NSMenuItem" id="586577488"> -						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">View</string> -						<string key="NSKeyEquiv"/> -						<int key="NSKeyEquivModMask">1048576</int> -						<int key="NSMnemonicLoc">2147483647</int> -						<reference key="NSOnImage" ref="35465992"/> -						<reference key="NSMixedImage" ref="502551668"/> -						<string key="NSAction">submenuAction:</string> -						<object class="NSMenu" key="NSSubmenu" id="466310130"> -							<string key="NSTitle">View</string> -							<object class="NSMutableArray" key="NSMenuItems"> -								<bool key="EncodedWithXMLCoder">YES</bool> -								<object class="NSMenuItem" id="102151532"> -									<reference key="NSMenu" ref="466310130"/> -									<string key="NSTitle">Show Toolbar</string> -									<string key="NSKeyEquiv">t</string> -									<int key="NSKeyEquivModMask">1572864</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="237841660"> -									<reference key="NSMenu" ref="466310130"/> -									<string type="base64-UTF8" key="NSTitle">Q3VzdG9taXplIFRvb2xiYXLigKY</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -							</object> -						</object> -					</object> -					<object class="NSMenuItem" id="713487014"> -						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">Window</string> -						<string key="NSKeyEquiv"/> -						<int key="NSKeyEquivModMask">1048576</int> -						<int key="NSMnemonicLoc">2147483647</int> -						<reference key="NSOnImage" ref="35465992"/> -						<reference key="NSMixedImage" ref="502551668"/> -						<string key="NSAction">submenuAction:</string> -						<object class="NSMenu" key="NSSubmenu" id="835318025"> -							<string key="NSTitle">Window</string> -							<object class="NSMutableArray" key="NSMenuItems"> -								<bool key="EncodedWithXMLCoder">YES</bool> -								<object class="NSMenuItem" id="1011231497"> -									<reference key="NSMenu" ref="835318025"/> -									<string key="NSTitle">Minimize</string> -									<string key="NSKeyEquiv">m</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="575023229"> -									<reference key="NSMenu" ref="835318025"/> -									<string key="NSTitle">Zoom</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="299356726"> -									<reference key="NSMenu" ref="835318025"/> -									<bool key="NSIsDisabled">YES</bool> -									<bool key="NSIsSeparator">YES</bool> -									<string key="NSTitle"/> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -								<object class="NSMenuItem" id="625202149"> -									<reference key="NSMenu" ref="835318025"/> -									<string key="NSTitle">Bring All to Front</string> -									<string key="NSKeyEquiv"/> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -							</object> -							<string key="NSName">_NSWindowsMenu</string> -						</object> -					</object> -					<object class="NSMenuItem" id="391199113"> -						<reference key="NSMenu" ref="649796088"/> -						<string key="NSTitle">Help</string> -						<string key="NSKeyEquiv"/> -						<int key="NSKeyEquivModMask">1048576</int> -						<int key="NSMnemonicLoc">2147483647</int> -						<reference key="NSOnImage" ref="35465992"/> -						<reference key="NSMixedImage" ref="502551668"/> -						<string key="NSAction">submenuAction:</string> -						<object class="NSMenu" key="NSSubmenu" id="374024848"> -							<string key="NSTitle">Help</string> -							<object class="NSMutableArray" key="NSMenuItems"> -								<bool key="EncodedWithXMLCoder">YES</bool> -								<object class="NSMenuItem" id="238773614"> -									<reference key="NSMenu" ref="374024848"/> -									<string key="NSTitle">NewApplication Help</string> -									<string key="NSKeyEquiv">?</string> -									<int key="NSKeyEquivModMask">1048576</int> -									<int key="NSMnemonicLoc">2147483647</int> -									<reference key="NSOnImage" ref="35465992"/> -									<reference key="NSMixedImage" ref="502551668"/> -								</object> -							</object> -						</object> -					</object>  				</object>  				<string key="NSName">_NSMainMenu</string>  			</object> -			<object class="NSCustomObject" id="755631768"> -				<string key="NSClassName">NSFontManager</string> -			</object>  			<object class="NSCustomObject" id="16040424">  				<string key="NSClassName">MainController</string>  			</object> @@ -1122,46 +188,6 @@  				<bool key="EncodedWithXMLCoder">YES</bool>  				<object class="IBConnectionRecord">  					<object class="IBActionConnection" key="connection"> -						<string key="label">performMiniaturize:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="1011231497"/> -					</object> -					<int key="connectionID">37</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">arrangeInFront:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="625202149"/> -					</object> -					<int key="connectionID">39</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">print:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="49223823"/> -					</object> -					<int key="connectionID">86</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">runPageLayout:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="294629803"/> -					</object> -					<int key="connectionID">87</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">clearRecentDocuments:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="759406840"/> -					</object> -					<int key="connectionID">127</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection">  						<string key="label">orderFrontStandardAboutPanel:</string>  						<reference key="source" ref="1021"/>  						<reference key="destination" ref="238522557"/> @@ -1170,214 +196,6 @@  				</object>  				<object class="IBConnectionRecord">  					<object class="IBActionConnection" key="connection"> -						<string key="label">performClose:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="776162233"/> -					</object> -					<int key="connectionID">193</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleContinuousSpellChecking:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="948374510"/> -					</object> -					<int key="connectionID">222</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">undo:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="1058277027"/> -					</object> -					<int key="connectionID">223</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">copy:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="860595796"/> -					</object> -					<int key="connectionID">224</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">checkSpelling:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="96193923"/> -					</object> -					<int key="connectionID">225</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">paste:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="29853731"/> -					</object> -					<int key="connectionID">226</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">stopSpeaking:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="680220178"/> -					</object> -					<int key="connectionID">227</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">cut:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="296257095"/> -					</object> -					<int key="connectionID">228</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">showGuessPanel:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="679648819"/> -					</object> -					<int key="connectionID">230</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">redo:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="790794224"/> -					</object> -					<int key="connectionID">231</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">selectAll:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="583158037"/> -					</object> -					<int key="connectionID">232</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">startSpeaking:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="731782645"/> -					</object> -					<int key="connectionID">233</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">delete:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="437104165"/> -					</object> -					<int key="connectionID">235</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">performZoom:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="575023229"/> -					</object> -					<int key="connectionID">240</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">performFindPanelAction:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="447796847"/> -					</object> -					<int key="connectionID">241</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">centerSelectionInVisibleArea:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="88285865"/> -					</object> -					<int key="connectionID">245</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleGrammarChecking:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="967646866"/> -					</object> -					<int key="connectionID">347</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleSmartInsertDelete:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="605118523"/> -					</object> -					<int key="connectionID">355</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleAutomaticQuoteSubstitution:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="197661976"/> -					</object> -					<int key="connectionID">356</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleAutomaticLinkDetection:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="708854459"/> -					</object> -					<int key="connectionID">357</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">showHelp:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="238773614"/> -					</object> -					<int key="connectionID">360</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">saveDocument:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="1023925487"/> -					</object> -					<int key="connectionID">362</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">saveDocumentAs:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="117038363"/> -					</object> -					<int key="connectionID">363</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">revertDocumentToSaved:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="579971712"/> -					</object> -					<int key="connectionID">364</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">runToolbarCustomizationPalette:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="237841660"/> -					</object> -					<int key="connectionID">365</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleToolbarShown:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="102151532"/> -					</object> -					<int key="connectionID">366</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection">  						<string key="label">hide:</string>  						<reference key="source" ref="1014"/>  						<reference key="destination" ref="755159360"/> @@ -1402,246 +220,6 @@  				</object>  				<object class="IBConnectionRecord">  					<object class="IBActionConnection" key="connection"> -						<string key="label">newDocument:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="705341025"/> -					</object> -					<int key="connectionID">373</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">openDocument:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="722745758"/> -					</object> -					<int key="connectionID">374</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">addFontTrait:</string> -						<reference key="source" ref="755631768"/> -						<reference key="destination" ref="305399458"/> -					</object> -					<int key="connectionID">421</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">addFontTrait:</string> -						<reference key="source" ref="755631768"/> -						<reference key="destination" ref="814362025"/> -					</object> -					<int key="connectionID">422</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">modifyFont:</string> -						<reference key="source" ref="755631768"/> -						<reference key="destination" ref="885547335"/> -					</object> -					<int key="connectionID">423</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">orderFrontFontPanel:</string> -						<reference key="source" ref="755631768"/> -						<reference key="destination" ref="159677712"/> -					</object> -					<int key="connectionID">424</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">modifyFont:</string> -						<reference key="source" ref="755631768"/> -						<reference key="destination" ref="158063935"/> -					</object> -					<int key="connectionID">425</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">raiseBaseline:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="941806246"/> -					</object> -					<int key="connectionID">426</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">lowerBaseline:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="1045724900"/> -					</object> -					<int key="connectionID">427</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">copyFont:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="596732606"/> -					</object> -					<int key="connectionID">428</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">subscript:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="1037576581"/> -					</object> -					<int key="connectionID">429</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">superscript:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="644725453"/> -					</object> -					<int key="connectionID">430</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">tightenKerning:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="677519740"/> -					</object> -					<int key="connectionID">431</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">underline:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="330926929"/> -					</object> -					<int key="connectionID">432</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">orderFrontColorPanel:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="1012600125"/> -					</object> -					<int key="connectionID">433</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">useAllLigatures:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="663508465"/> -					</object> -					<int key="connectionID">434</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">loosenKerning:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="238351151"/> -					</object> -					<int key="connectionID">435</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">pasteFont:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="393423671"/> -					</object> -					<int key="connectionID">436</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">unscript:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="257962622"/> -					</object> -					<int key="connectionID">437</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">useStandardKerning:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="252969304"/> -					</object> -					<int key="connectionID">438</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">useStandardLigatures:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="706297211"/> -					</object> -					<int key="connectionID">439</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">turnOffLigatures:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="568384683"/> -					</object> -					<int key="connectionID">440</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">turnOffKerning:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="766922938"/> -					</object> -					<int key="connectionID">441</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">alignLeft:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="135107054"/> -					</object> -					<int key="connectionID">442</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">alignJustified:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="436088763"/> -					</object> -					<int key="connectionID">443</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">copyRuler:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="479856769"/> -					</object> -					<int key="connectionID">444</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">alignCenter:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="310547522"/> -					</object> -					<int key="connectionID">445</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">toggleRuler:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="420564933"/> -					</object> -					<int key="connectionID">446</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">alignRight:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="498119243"/> -					</object> -					<int key="connectionID">447</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection"> -						<string key="label">pasteRuler:</string> -						<reference key="source" ref="1014"/> -						<reference key="destination" ref="333628178"/> -					</object> -					<int key="connectionID">448</int> -				</object> -				<object class="IBConnectionRecord"> -					<object class="IBActionConnection" key="connection">  						<string key="label">terminate:</string>  						<reference key="source" ref="1050"/>  						<reference key="destination" ref="632727374"/> @@ -1683,25 +261,15 @@  						<reference key="object" ref="649796088"/>  						<object class="NSMutableArray" key="children">  							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="713487014"/>  							<reference ref="694149608"/> -							<reference ref="391199113"/> -							<reference ref="952259628"/> -							<reference ref="379814623"/> -							<reference ref="586577488"/> -							<reference ref="302598603"/>  						</object>  						<reference key="parent" ref="1049"/>  						<string key="objectName">MainMenu</string>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">19</int> -						<reference key="object" ref="713487014"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="835318025"/> -						</object> -						<reference key="parent" ref="649796088"/> +						<int key="objectID">458</int> +						<reference key="object" ref="16040424"/> +						<reference key="parent" ref="1049"/>  					</object>  					<object class="IBObjectRecord">  						<int key="objectID">56</int> @@ -1713,357 +281,32 @@  						<reference key="parent" ref="649796088"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">103</int> -						<reference key="object" ref="391199113"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="374024848"/> -						</object> -						<reference key="parent" ref="649796088"/> -						<string key="objectName">1</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">217</int> -						<reference key="object" ref="952259628"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="789758025"/> -						</object> -						<reference key="parent" ref="649796088"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">83</int> -						<reference key="object" ref="379814623"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="720053764"/> -						</object> -						<reference key="parent" ref="649796088"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">81</int> -						<reference key="object" ref="720053764"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="1023925487"/> -							<reference ref="117038363"/> -							<reference ref="49223823"/> -							<reference ref="722745758"/> -							<reference ref="705341025"/> -							<reference ref="1025936716"/> -							<reference ref="294629803"/> -							<reference ref="776162233"/> -							<reference ref="425164168"/> -							<reference ref="579971712"/> -							<reference ref="1010469920"/> -						</object> -						<reference key="parent" ref="379814623"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">75</int> -						<reference key="object" ref="1023925487"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">3</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">80</int> -						<reference key="object" ref="117038363"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">8</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">78</int> -						<reference key="object" ref="49223823"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">6</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">72</int> -						<reference key="object" ref="722745758"/> -						<reference key="parent" ref="720053764"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">82</int> -						<reference key="object" ref="705341025"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">9</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">124</int> -						<reference key="object" ref="1025936716"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="1065607017"/> -						</object> -						<reference key="parent" ref="720053764"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">77</int> -						<reference key="object" ref="294629803"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">5</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">73</int> -						<reference key="object" ref="776162233"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">1</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">79</int> -						<reference key="object" ref="425164168"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">7</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">112</int> -						<reference key="object" ref="579971712"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">10</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">74</int> -						<reference key="object" ref="1010469920"/> -						<reference key="parent" ref="720053764"/> -						<string key="objectName">2</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">125</int> -						<reference key="object" ref="1065607017"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="759406840"/> -						</object> -						<reference key="parent" ref="1025936716"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">126</int> -						<reference key="object" ref="759406840"/> -						<reference key="parent" ref="1065607017"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">205</int> -						<reference key="object" ref="789758025"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="437104165"/> -							<reference ref="583158037"/> -							<reference ref="1058277027"/> -							<reference ref="212016141"/> -							<reference ref="296257095"/> -							<reference ref="29853731"/> -							<reference ref="860595796"/> -							<reference ref="1040322652"/> -							<reference ref="790794224"/> -							<reference ref="892235320"/> -							<reference ref="972420730"/> -							<reference ref="676164635"/> -							<reference ref="507821607"/> -						</object> -						<reference key="parent" ref="952259628"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">202</int> -						<reference key="object" ref="437104165"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">198</int> -						<reference key="object" ref="583158037"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">207</int> -						<reference key="object" ref="1058277027"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">214</int> -						<reference key="object" ref="212016141"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">199</int> -						<reference key="object" ref="296257095"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">203</int> -						<reference key="object" ref="29853731"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">197</int> -						<reference key="object" ref="860595796"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">206</int> -						<reference key="object" ref="1040322652"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">215</int> -						<reference key="object" ref="790794224"/> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">218</int> -						<reference key="object" ref="892235320"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="963351320"/> -						</object> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">216</int> -						<reference key="object" ref="972420730"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="769623530"/> -						</object> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">200</int> -						<reference key="object" ref="769623530"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="948374510"/> -							<reference ref="96193923"/> -							<reference ref="679648819"/> -							<reference ref="967646866"/> -						</object> -						<reference key="parent" ref="972420730"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">219</int> -						<reference key="object" ref="948374510"/> -						<reference key="parent" ref="769623530"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">201</int> -						<reference key="object" ref="96193923"/> -						<reference key="parent" ref="769623530"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">204</int> -						<reference key="object" ref="679648819"/> -						<reference key="parent" ref="769623530"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">220</int> -						<reference key="object" ref="963351320"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="270902937"/> -							<reference ref="88285865"/> -							<reference ref="159080638"/> -							<reference ref="326711663"/> -							<reference ref="447796847"/> -						</object> -						<reference key="parent" ref="892235320"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">213</int> -						<reference key="object" ref="270902937"/> -						<reference key="parent" ref="963351320"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">210</int> -						<reference key="object" ref="88285865"/> -						<reference key="parent" ref="963351320"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">221</int> -						<reference key="object" ref="159080638"/> -						<reference key="parent" ref="963351320"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">208</int> -						<reference key="object" ref="326711663"/> -						<reference key="parent" ref="963351320"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">209</int> -						<reference key="object" ref="447796847"/> -						<reference key="parent" ref="963351320"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">106</int> -						<reference key="object" ref="374024848"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="238773614"/> -						</object> -						<reference key="parent" ref="391199113"/> -						<string key="objectName">2</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">111</int> -						<reference key="object" ref="238773614"/> -						<reference key="parent" ref="374024848"/> -					</object> -					<object class="IBObjectRecord">  						<int key="objectID">57</int>  						<reference key="object" ref="110575045"/>  						<object class="NSMutableArray" key="children">  							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="238522557"/> -							<reference ref="755159360"/> -							<reference ref="908899353"/> -							<reference ref="632727374"/> -							<reference ref="646227648"/> -							<reference ref="609285721"/> -							<reference ref="481834944"/> -							<reference ref="304266470"/> -							<reference ref="1046388886"/> -							<reference ref="1056857174"/>  							<reference ref="342932134"/> +							<reference ref="1056857174"/> +							<reference ref="1046388886"/> +							<reference ref="304266470"/> +							<reference ref="481834944"/> +							<reference ref="609285721"/> +							<reference ref="646227648"/> +							<reference ref="632727374"/> +							<reference ref="908899353"/> +							<reference ref="755159360"/> +							<reference ref="238522557"/>  						</object>  						<reference key="parent" ref="694149608"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">58</int> -						<reference key="object" ref="238522557"/> -						<reference key="parent" ref="110575045"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">134</int> -						<reference key="object" ref="755159360"/> -						<reference key="parent" ref="110575045"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">150</int> -						<reference key="object" ref="908899353"/> -						<reference key="parent" ref="110575045"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">136</int> -						<reference key="object" ref="632727374"/> -						<reference key="parent" ref="110575045"/> -						<string key="objectName">1111</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">144</int> -						<reference key="object" ref="646227648"/> -						<reference key="parent" ref="110575045"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">129</int> -						<reference key="object" ref="609285721"/> -						<reference key="parent" ref="110575045"/> -						<string key="objectName">121</string> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">143</int> -						<reference key="object" ref="481834944"/> +						<int key="objectID">145</int> +						<reference key="object" ref="342932134"/>  						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">236</int> -						<reference key="object" ref="304266470"/> +						<int key="objectID">149</int> +						<reference key="object" ref="1056857174"/>  						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> @@ -2076,464 +319,51 @@  						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">149</int> -						<reference key="object" ref="1056857174"/> -						<reference key="parent" ref="110575045"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">145</int> -						<reference key="object" ref="342932134"/> -						<reference key="parent" ref="110575045"/> -					</object> -					<object class="IBObjectRecord">  						<int key="objectID">130</int>  						<reference key="object" ref="752062318"/>  						<reference key="parent" ref="1046388886"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">24</int> -						<reference key="object" ref="835318025"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="299356726"/> -							<reference ref="625202149"/> -							<reference ref="575023229"/> -							<reference ref="1011231497"/> -						</object> -						<reference key="parent" ref="713487014"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">92</int> -						<reference key="object" ref="299356726"/> -						<reference key="parent" ref="835318025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">5</int> -						<reference key="object" ref="625202149"/> -						<reference key="parent" ref="835318025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">239</int> -						<reference key="object" ref="575023229"/> -						<reference key="parent" ref="835318025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">23</int> -						<reference key="object" ref="1011231497"/> -						<reference key="parent" ref="835318025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">295</int> -						<reference key="object" ref="586577488"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="466310130"/> -						</object> -						<reference key="parent" ref="649796088"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">296</int> -						<reference key="object" ref="466310130"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="102151532"/> -							<reference ref="237841660"/> -						</object> -						<reference key="parent" ref="586577488"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">297</int> -						<reference key="object" ref="102151532"/> -						<reference key="parent" ref="466310130"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">298</int> -						<reference key="object" ref="237841660"/> -						<reference key="parent" ref="466310130"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">211</int> -						<reference key="object" ref="676164635"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="785027613"/> -						</object> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">212</int> -						<reference key="object" ref="785027613"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="680220178"/> -							<reference ref="731782645"/> -						</object> -						<reference key="parent" ref="676164635"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">195</int> -						<reference key="object" ref="680220178"/> -						<reference key="parent" ref="785027613"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">196</int> -						<reference key="object" ref="731782645"/> -						<reference key="parent" ref="785027613"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">346</int> -						<reference key="object" ref="967646866"/> -						<reference key="parent" ref="769623530"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">348</int> -						<reference key="object" ref="507821607"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="698887838"/> -						</object> -						<reference key="parent" ref="789758025"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">349</int> -						<reference key="object" ref="698887838"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="605118523"/> -							<reference ref="197661976"/> -							<reference ref="708854459"/> -						</object> -						<reference key="parent" ref="507821607"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">350</int> -						<reference key="object" ref="605118523"/> -						<reference key="parent" ref="698887838"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">351</int> -						<reference key="object" ref="197661976"/> -						<reference key="parent" ref="698887838"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">354</int> -						<reference key="object" ref="708854459"/> -						<reference key="parent" ref="698887838"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">375</int> -						<reference key="object" ref="302598603"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="941447902"/> -						</object> -						<reference key="parent" ref="649796088"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">376</int> -						<reference key="object" ref="941447902"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="792887677"/> -							<reference ref="15516124"/> -						</object> -						<reference key="parent" ref="302598603"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">377</int> -						<reference key="object" ref="792887677"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="786677654"/> -						</object> -						<reference key="parent" ref="941447902"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">378</int> -						<reference key="object" ref="15516124"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="23081656"/> -						</object> -						<reference key="parent" ref="941447902"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">379</int> -						<reference key="object" ref="23081656"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="135107054"/> -							<reference ref="310547522"/> -							<reference ref="436088763"/> -							<reference ref="498119243"/> -							<reference ref="607995063"/> -							<reference ref="420564933"/> -							<reference ref="479856769"/> -							<reference ref="333628178"/> -						</object> -						<reference key="parent" ref="15516124"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">380</int> -						<reference key="object" ref="135107054"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">381</int> -						<reference key="object" ref="310547522"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">382</int> -						<reference key="object" ref="436088763"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">383</int> -						<reference key="object" ref="498119243"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">384</int> -						<reference key="object" ref="607995063"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">385</int> -						<reference key="object" ref="420564933"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">386</int> -						<reference key="object" ref="479856769"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">387</int> -						<reference key="object" ref="333628178"/> -						<reference key="parent" ref="23081656"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">388</int> -						<reference key="object" ref="786677654"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="159677712"/> -							<reference ref="305399458"/> -							<reference ref="814362025"/> -							<reference ref="330926929"/> -							<reference ref="533507878"/> -							<reference ref="158063935"/> -							<reference ref="885547335"/> -							<reference ref="901062459"/> -							<reference ref="767671776"/> -							<reference ref="691570813"/> -							<reference ref="769124883"/> -							<reference ref="739652853"/> -							<reference ref="1012600125"/> -							<reference ref="214559597"/> -							<reference ref="596732606"/> -							<reference ref="393423671"/> -						</object> -						<reference key="parent" ref="792887677"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">389</int> -						<reference key="object" ref="159677712"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">390</int> -						<reference key="object" ref="305399458"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">391</int> -						<reference key="object" ref="814362025"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">392</int> -						<reference key="object" ref="330926929"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">393</int> -						<reference key="object" ref="533507878"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">394</int> -						<reference key="object" ref="158063935"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">395</int> -						<reference key="object" ref="885547335"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">396</int> -						<reference key="object" ref="901062459"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">397</int> -						<reference key="object" ref="767671776"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="175441468"/> -						</object> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">398</int> -						<reference key="object" ref="691570813"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="1058217995"/> -						</object> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">399</int> -						<reference key="object" ref="769124883"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="18263474"/> -						</object> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">400</int> -						<reference key="object" ref="739652853"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">401</int> -						<reference key="object" ref="1012600125"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">402</int> -						<reference key="object" ref="214559597"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">403</int> -						<reference key="object" ref="596732606"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">404</int> -						<reference key="object" ref="393423671"/> -						<reference key="parent" ref="786677654"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">405</int> -						<reference key="object" ref="18263474"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="257962622"/> -							<reference ref="644725453"/> -							<reference ref="1037576581"/> -							<reference ref="941806246"/> -							<reference ref="1045724900"/> -						</object> -						<reference key="parent" ref="769124883"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">406</int> -						<reference key="object" ref="257962622"/> -						<reference key="parent" ref="18263474"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">407</int> -						<reference key="object" ref="644725453"/> -						<reference key="parent" ref="18263474"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">408</int> -						<reference key="object" ref="1037576581"/> -						<reference key="parent" ref="18263474"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">409</int> -						<reference key="object" ref="941806246"/> -						<reference key="parent" ref="18263474"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">410</int> -						<reference key="object" ref="1045724900"/> -						<reference key="parent" ref="18263474"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">411</int> -						<reference key="object" ref="1058217995"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="706297211"/> -							<reference ref="568384683"/> -							<reference ref="663508465"/> -						</object> -						<reference key="parent" ref="691570813"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">412</int> -						<reference key="object" ref="706297211"/> -						<reference key="parent" ref="1058217995"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">413</int> -						<reference key="object" ref="568384683"/> -						<reference key="parent" ref="1058217995"/> -					</object> -					<object class="IBObjectRecord"> -						<int key="objectID">414</int> -						<reference key="object" ref="663508465"/> -						<reference key="parent" ref="1058217995"/> +						<int key="objectID">236</int> +						<reference key="object" ref="304266470"/> +						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">415</int> -						<reference key="object" ref="175441468"/> -						<object class="NSMutableArray" key="children"> -							<bool key="EncodedWithXMLCoder">YES</bool> -							<reference ref="252969304"/> -							<reference ref="766922938"/> -							<reference ref="677519740"/> -							<reference ref="238351151"/> -						</object> -						<reference key="parent" ref="767671776"/> +						<int key="objectID">143</int> +						<reference key="object" ref="481834944"/> +						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">416</int> -						<reference key="object" ref="252969304"/> -						<reference key="parent" ref="175441468"/> +						<int key="objectID">129</int> +						<reference key="object" ref="609285721"/> +						<reference key="parent" ref="110575045"/> +						<string key="objectName">121</string>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">417</int> -						<reference key="object" ref="766922938"/> -						<reference key="parent" ref="175441468"/> +						<int key="objectID">144</int> +						<reference key="object" ref="646227648"/> +						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">418</int> -						<reference key="object" ref="677519740"/> -						<reference key="parent" ref="175441468"/> +						<int key="objectID">136</int> +						<reference key="object" ref="632727374"/> +						<reference key="parent" ref="110575045"/> +						<string key="objectName">1111</string>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">419</int> -						<reference key="object" ref="238351151"/> -						<reference key="parent" ref="175441468"/> +						<int key="objectID">150</int> +						<reference key="object" ref="908899353"/> +						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">420</int> -						<reference key="object" ref="755631768"/> -						<reference key="parent" ref="1049"/> +						<int key="objectID">134</int> +						<reference key="object" ref="755159360"/> +						<reference key="parent" ref="110575045"/>  					</object>  					<object class="IBObjectRecord"> -						<int key="objectID">458</int> -						<reference key="object" ref="16040424"/> -						<reference key="parent" ref="1049"/> +						<int key="objectID">58</int> +						<reference key="object" ref="238522557"/> +						<reference key="parent" ref="110575045"/>  					</object>  				</object>  			</object> @@ -2544,22 +374,6 @@  					<string>-1.IBPluginDependency</string>  					<string>-2.IBPluginDependency</string>  					<string>-3.IBPluginDependency</string> -					<string>103.IBPluginDependency</string> -					<string>103.ImportedFromIB2</string> -					<string>106.IBPluginDependency</string> -					<string>106.ImportedFromIB2</string> -					<string>106.editorWindowContentRectSynchronizationRect</string> -					<string>111.IBPluginDependency</string> -					<string>111.ImportedFromIB2</string> -					<string>112.IBPluginDependency</string> -					<string>112.ImportedFromIB2</string> -					<string>124.IBPluginDependency</string> -					<string>124.ImportedFromIB2</string> -					<string>125.IBPluginDependency</string> -					<string>125.ImportedFromIB2</string> -					<string>125.editorWindowContentRectSynchronizationRect</string> -					<string>126.IBPluginDependency</string> -					<string>126.ImportedFromIB2</string>  					<string>129.IBPluginDependency</string>  					<string>129.ImportedFromIB2</string>  					<string>130.IBPluginDependency</string> @@ -2581,150 +395,14 @@  					<string>149.ImportedFromIB2</string>  					<string>150.IBPluginDependency</string>  					<string>150.ImportedFromIB2</string> -					<string>19.IBPluginDependency</string> -					<string>19.ImportedFromIB2</string> -					<string>195.IBPluginDependency</string> -					<string>195.ImportedFromIB2</string> -					<string>196.IBPluginDependency</string> -					<string>196.ImportedFromIB2</string> -					<string>197.IBPluginDependency</string> -					<string>197.ImportedFromIB2</string> -					<string>198.IBPluginDependency</string> -					<string>198.ImportedFromIB2</string> -					<string>199.IBPluginDependency</string> -					<string>199.ImportedFromIB2</string> -					<string>200.IBPluginDependency</string> -					<string>200.ImportedFromIB2</string> -					<string>200.editorWindowContentRectSynchronizationRect</string> -					<string>201.IBPluginDependency</string> -					<string>201.ImportedFromIB2</string> -					<string>202.IBPluginDependency</string> -					<string>202.ImportedFromIB2</string> -					<string>203.IBPluginDependency</string> -					<string>203.ImportedFromIB2</string> -					<string>204.IBPluginDependency</string> -					<string>204.ImportedFromIB2</string> -					<string>205.IBEditorWindowLastContentRect</string> -					<string>205.IBPluginDependency</string> -					<string>205.ImportedFromIB2</string> -					<string>205.editorWindowContentRectSynchronizationRect</string> -					<string>206.IBPluginDependency</string> -					<string>206.ImportedFromIB2</string> -					<string>207.IBPluginDependency</string> -					<string>207.ImportedFromIB2</string> -					<string>208.IBPluginDependency</string> -					<string>208.ImportedFromIB2</string> -					<string>209.IBPluginDependency</string> -					<string>209.ImportedFromIB2</string> -					<string>210.IBPluginDependency</string> -					<string>210.ImportedFromIB2</string> -					<string>211.IBPluginDependency</string> -					<string>211.ImportedFromIB2</string> -					<string>212.IBPluginDependency</string> -					<string>212.ImportedFromIB2</string> -					<string>212.editorWindowContentRectSynchronizationRect</string> -					<string>213.IBPluginDependency</string> -					<string>213.ImportedFromIB2</string> -					<string>214.IBPluginDependency</string> -					<string>214.ImportedFromIB2</string> -					<string>215.IBPluginDependency</string> -					<string>215.ImportedFromIB2</string> -					<string>216.IBPluginDependency</string> -					<string>216.ImportedFromIB2</string> -					<string>217.IBPluginDependency</string> -					<string>217.ImportedFromIB2</string> -					<string>218.IBPluginDependency</string> -					<string>218.ImportedFromIB2</string> -					<string>219.IBPluginDependency</string> -					<string>219.ImportedFromIB2</string> -					<string>220.IBPluginDependency</string> -					<string>220.ImportedFromIB2</string> -					<string>220.editorWindowContentRectSynchronizationRect</string> -					<string>221.IBPluginDependency</string> -					<string>221.ImportedFromIB2</string> -					<string>23.IBPluginDependency</string> -					<string>23.ImportedFromIB2</string>  					<string>236.IBPluginDependency</string>  					<string>236.ImportedFromIB2</string> -					<string>239.IBPluginDependency</string> -					<string>239.ImportedFromIB2</string> -					<string>24.IBPluginDependency</string> -					<string>24.ImportedFromIB2</string> -					<string>24.editorWindowContentRectSynchronizationRect</string>  					<string>29.IBEditorWindowLastContentRect</string>  					<string>29.IBPluginDependency</string>  					<string>29.ImportedFromIB2</string>  					<string>29.WindowOrigin</string>  					<string>29.editorWindowContentRectSynchronizationRect</string> -					<string>295.IBPluginDependency</string> -					<string>296.IBPluginDependency</string> -					<string>296.editorWindowContentRectSynchronizationRect</string> -					<string>297.IBPluginDependency</string> -					<string>298.IBPluginDependency</string> -					<string>346.IBPluginDependency</string> -					<string>346.ImportedFromIB2</string> -					<string>348.IBPluginDependency</string> -					<string>348.ImportedFromIB2</string> -					<string>349.IBPluginDependency</string> -					<string>349.ImportedFromIB2</string> -					<string>349.editorWindowContentRectSynchronizationRect</string> -					<string>350.IBPluginDependency</string> -					<string>350.ImportedFromIB2</string> -					<string>351.IBPluginDependency</string> -					<string>351.ImportedFromIB2</string> -					<string>354.IBPluginDependency</string> -					<string>354.ImportedFromIB2</string> -					<string>375.IBPluginDependency</string> -					<string>376.IBEditorWindowLastContentRect</string> -					<string>376.IBPluginDependency</string> -					<string>377.IBPluginDependency</string> -					<string>378.IBPluginDependency</string> -					<string>379.IBPluginDependency</string> -					<string>380.IBPluginDependency</string> -					<string>381.IBPluginDependency</string> -					<string>382.IBPluginDependency</string> -					<string>383.IBPluginDependency</string> -					<string>384.IBPluginDependency</string> -					<string>385.IBPluginDependency</string> -					<string>386.IBPluginDependency</string> -					<string>387.IBPluginDependency</string> -					<string>388.IBEditorWindowLastContentRect</string> -					<string>388.IBPluginDependency</string> -					<string>389.IBPluginDependency</string> -					<string>390.IBPluginDependency</string> -					<string>391.IBPluginDependency</string> -					<string>392.IBPluginDependency</string> -					<string>393.IBPluginDependency</string> -					<string>394.IBPluginDependency</string> -					<string>395.IBPluginDependency</string> -					<string>396.IBPluginDependency</string> -					<string>397.IBPluginDependency</string> -					<string>398.IBPluginDependency</string> -					<string>399.IBPluginDependency</string> -					<string>400.IBPluginDependency</string> -					<string>401.IBPluginDependency</string> -					<string>402.IBPluginDependency</string> -					<string>403.IBPluginDependency</string> -					<string>404.IBPluginDependency</string> -					<string>405.IBPluginDependency</string> -					<string>406.IBPluginDependency</string> -					<string>407.IBPluginDependency</string> -					<string>408.IBPluginDependency</string> -					<string>409.IBPluginDependency</string> -					<string>410.IBPluginDependency</string> -					<string>411.IBPluginDependency</string> -					<string>412.IBPluginDependency</string> -					<string>413.IBPluginDependency</string> -					<string>414.IBPluginDependency</string> -					<string>415.IBPluginDependency</string> -					<string>416.IBPluginDependency</string> -					<string>417.IBPluginDependency</string> -					<string>418.IBPluginDependency</string> -					<string>419.IBPluginDependency</string> -					<string>420.IBPluginDependency</string>  					<string>458.IBPluginDependency</string> -					<string>5.IBPluginDependency</string> -					<string>5.ImportedFromIB2</string>  					<string>56.IBPluginDependency</string>  					<string>56.ImportedFromIB2</string>  					<string>57.IBEditorWindowLastContentRect</string> @@ -2733,32 +411,6 @@  					<string>57.editorWindowContentRectSynchronizationRect</string>  					<string>58.IBPluginDependency</string>  					<string>58.ImportedFromIB2</string> -					<string>72.IBPluginDependency</string> -					<string>72.ImportedFromIB2</string> -					<string>73.IBPluginDependency</string> -					<string>73.ImportedFromIB2</string> -					<string>74.IBPluginDependency</string> -					<string>74.ImportedFromIB2</string> -					<string>75.IBPluginDependency</string> -					<string>75.ImportedFromIB2</string> -					<string>77.IBPluginDependency</string> -					<string>77.ImportedFromIB2</string> -					<string>78.IBPluginDependency</string> -					<string>78.ImportedFromIB2</string> -					<string>79.IBPluginDependency</string> -					<string>79.ImportedFromIB2</string> -					<string>80.IBPluginDependency</string> -					<string>80.ImportedFromIB2</string> -					<string>81.IBEditorWindowLastContentRect</string> -					<string>81.IBPluginDependency</string> -					<string>81.ImportedFromIB2</string> -					<string>81.editorWindowContentRectSynchronizationRect</string> -					<string>82.IBPluginDependency</string> -					<string>82.ImportedFromIB2</string> -					<string>83.IBPluginDependency</string> -					<string>83.ImportedFromIB2</string> -					<string>92.IBPluginDependency</string> -					<string>92.ImportedFromIB2</string>  				</object>  				<object class="NSMutableArray" key="dict.values">  					<bool key="EncodedWithXMLCoder">YES</bool> @@ -2769,22 +421,6 @@  					<integer value="1" id="9"/>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/> -					<string>{{596, 852}, {216, 23}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{522, 812}, {146, 23}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/>  					<string>{{436, 809}, {64, 6}}</string>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/> @@ -2804,182 +440,20 @@  					<reference ref="9"/>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{608, 612}, {275, 83}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{492, 116}, {243, 243}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{187, 434}, {243, 243}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{608, 612}, {167, 43}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{608, 612}, {241, 103}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{525, 802}, {197, 73}}</string> -					<string>{{306, 359}, {478, 20}}</string> +					<string>{{306, 359}, {97, 20}}</string>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/>  					<string>{74, 862}</string>  					<string>{{6, 978}, {478, 20}}</string>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>{{475, 832}, {234, 43}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{608, 612}, {215, 63}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>{{437, 242}, {86, 43}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>{{523, 2}, {178, 283}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/> -					<string>{{318, 176}, {245, 183}}</string> +					<string>{{318, 176}, {190, 183}}</string>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/>  					<string>{{23, 794}, {245, 183}}</string>  					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>  					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{450, 156}, {199, 203}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>{{145, 474}, {199, 203}}</string> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/> -					<string>com.apple.InterfaceBuilder.CocoaPlugin</string> -					<reference ref="9"/>  				</object>  			</object>  			<object class="NSMutableDictionary" key="unlocalizedProperties"> diff --git a/Slimber/Cocoa/Makefile.inc b/Slimber/Cocoa/Makefile.inc index 73b0f5d..8cd72cd 100644 --- a/Slimber/Cocoa/Makefile.inc +++ b/Slimber/Cocoa/Makefile.inc @@ -2,9 +2,6 @@ SLIMBER_COCOA_TARGET = Slimber/Cocoa/Slimber.app  SLIMBER_COCOA_BINARY = \  	Slimber/Cocoa/Slimber  SLIMBER_COCOA_SOURCES = \ -	Slimber/Server.cpp \ -	Slimber/VCardCollection.cpp \ -	Slimber/FileVCardCollection.cpp \  	Slimber/Cocoa/MainController.mm \  	Slimber/Cocoa/Slimber.mm \  	Slimber/Cocoa/main.mm \ @@ -12,6 +9,7 @@ SLIMBER_COCOA_SOURCES = \  SLIMBER_COCOA_XIBS = \  	Slimber/Cocoa/MainMenu.xib  SLIMBER_COCOA_RESOURCES = \ +	Slimber/Resources/Credits.html \  	Slimber/Resources/Online.png \  	Slimber/Resources/Offline.png \  	Slimber/Resources/UsersOnline.png \ @@ -25,7 +23,6 @@ SLIMBER_COCOA_OBJECTS = \  	$(patsubst %.m,%.o,$(patsubst %.mm,%.o,$(patsubst %.cpp,%.o, $(SLIMBER_COCOA_SOURCES))))  CLEANFILES += \  	Slimber/Cocoa/PkgInfo \ -	$(SLIMBER_COCOA_OBJECTS) \  	$(SLIMBER_COCOA_NIBS) \  	$(SLIMBER_COCOA_TARGET) \  	$(SLIMBER_COCOA_BINARY) @@ -45,5 +42,5 @@ $(SLIMBER_COCOA_TARGET): $(SLIMBER_COCOA_BINARY) $(SLIMBER_COCOA_NIBS) Slimber/C  	cp $(SLIMBER_COCOA_NIBS) $(SLIMBER_COCOA_TARGET)/Contents/Resources  	cp $(SLIMBER_COCOA_RESOURCES) $(SLIMBER_COCOA_TARGET)/Contents/Resources -$(SLIMBER_COCOA_BINARY): $(SLIMBER_COCOA_OBJECTS) $(SWIFTEN_TARGET) -	$(QUIET_LINK)$(CXX) -o $@ $(SLIMBER_COCOA_OBJECTS) $(LDFLAGS) $(SWIFTEN_TARGET) $(LIBS) -framework Cocoa +$(SLIMBER_COCOA_BINARY): $(SLIMBER_COCOA_OBJECTS) $(SWIFTEN_TARGET) $(SLIMBER_TRGET) +	$(QUIET_LINK)$(CXX) -o $@ $(SLIMBER_COCOA_OBJECTS) $(LDFLAGS) $(SLIMBER_TARGET) $(SWIFTEN_TARGET) $(LIBS) -framework Cocoa diff --git a/Slimber/Cocoa/Menulet.m b/Slimber/Cocoa/Menulet.m index b2af97f..1cc1f1f 100644 --- a/Slimber/Cocoa/Menulet.m +++ b/Slimber/Cocoa/Menulet.m @@ -49,8 +49,10 @@  		[statusMenu addItem: [[NSMenuItem alloc] initWithTitle: @"Online users:" action: NULL keyEquivalent: @""]];  		int i;  		for (i = 0; i < [userNames count]; ++i) { -			NSMenuItem* userItem = [[NSMenuItem alloc] initWithTitle: [@"  " stringByAppendingString: [userNames objectAtIndex: i]] action: NULL keyEquivalent: @""]; +			NSString* text = [NSString stringWithFormat: @"  %@", [userNames objectAtIndex: i]];  +			NSMenuItem* userItem = [[NSMenuItem alloc] initWithTitle: text action: NULL keyEquivalent: @""];  			[statusMenu addItem: userItem]; +			[userItem release];  		}  	}  	else { @@ -75,6 +77,12 @@  	[statusMenu addItem: loggedInItem];  	[statusMenu addItem: [NSMenuItem separatorItem]]; +	// About menu +	NSMenuItem* aboutMenuItem = [[NSMenuItem alloc] initWithTitle: @"About Slimber" action: @selector(orderFrontStandardAboutPanel:) keyEquivalent: @""]; +	[aboutMenuItem setTarget: [NSApplication sharedApplication]]; +	[statusMenu addItem: aboutMenuItem]; +	[statusMenu addItem: [NSMenuItem separatorItem]]; +  	// Exit item  	NSMenuItem* exitMenuItem = [[NSMenuItem alloc] initWithTitle: @"Exit" action: @selector(terminate:) keyEquivalent: @""];  	[exitMenuItem setTarget: [NSApplication sharedApplication]]; diff --git a/Slimber/Cocoa/Slimber.h b/Slimber/Cocoa/Slimber.h index c2c0e2d..b62f9e5 100644 --- a/Slimber/Cocoa/Slimber.h +++ b/Slimber/Cocoa/Slimber.h @@ -1,16 +1,13 @@  #pragma once -#include <string> -#include <boost/bind.hpp>  #include <boost/shared_ptr.hpp> -#include "Swiften/LinkLocal/DNSSDService.h" -#include "Swiften/LinkLocal/LinkLocalRoster.h" -  @class Menulet;  namespace Swift {  	class Server;  	class VCardCollection; +	class LinkLocalServiceBrowser; +	class BonjourQuerier;  }  class Slimber { @@ -20,11 +17,11 @@ class Slimber {  	private:  		void handleSelfConnected(bool b); -		void handleRosterChanged(); +		void handleServicesChanged();  	private: -		boost::shared_ptr<Swift::DNSSDService> dnsSDService; -		boost::shared_ptr<Swift::LinkLocalRoster>linkLocalRoster; +		boost::shared_ptr<Swift::BonjourQuerier> dnsSDQuerier; +		Swift::LinkLocalServiceBrowser* linkLocalServiceBrowser;  		Swift::VCardCollection* vCardCollection;  		Swift::Server* server;  		Menulet* menulet; diff --git a/Slimber/Cocoa/Slimber.mm b/Slimber/Cocoa/Slimber.mm index ae1d9fd..d4851c8 100644 --- a/Slimber/Cocoa/Slimber.mm +++ b/Slimber/Cocoa/Slimber.mm @@ -1,9 +1,12 @@  #include "Slimber/Cocoa/Slimber.h" +#include <boost/bind.hpp> +  #include "Swiften/Base/foreach.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/LinkLocal/AppleDNSSDService.h"  #include "Swiften/Application/Platform/PlatformApplication.h" +#include "Swiften/LinkLocal/LinkLocalService.h" +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h"  #include "Slimber/Cocoa/Menulet.h"  #include "Slimber/Server.h"  #include "Slimber/FileVCardCollection.h" @@ -11,37 +14,46 @@  using namespace Swift;  Slimber::Slimber() { -	dnsSDService = boost::shared_ptr<AppleDNSSDService>(new AppleDNSSDService()); +	dnsSDQuerier = boost::shared_ptr<BonjourQuerier>(new BonjourQuerier()); +	dnsSDQuerier->start(); -	linkLocalRoster = boost::shared_ptr<LinkLocalRoster>(new LinkLocalRoster(dnsSDService)); -	linkLocalRoster->onRosterChanged.connect(boost::bind(&Slimber::handleRosterChanged, this)); +	linkLocalServiceBrowser = new LinkLocalServiceBrowser(dnsSDQuerier); +	linkLocalServiceBrowser->onServiceAdded.connect( +			boost::bind(&Slimber::handleServicesChanged, this)); +	linkLocalServiceBrowser->onServiceRemoved.connect( +			boost::bind(&Slimber::handleServicesChanged, this)); +	linkLocalServiceBrowser->onServiceChanged.connect( +			boost::bind(&Slimber::handleServicesChanged, this)); +	linkLocalServiceBrowser->start(); -	vCardCollection = new FileVCardCollection(PlatformApplication("Slimber").getSettingsDir()); +	vCardCollection = new FileVCardCollection( +			PlatformApplication("Slimber").getSettingsDir()); -	server = new Server(5222, 5562, linkLocalRoster, dnsSDService, vCardCollection); -	server->onSelfConnected.connect(boost::bind(&Slimber::handleSelfConnected, this, _1)); +	server = new Server(5222, 5562, linkLocalServiceBrowser, vCardCollection); +	server->onSelfConnected.connect( +			boost::bind(&Slimber::handleSelfConnected, this, _1));  	menulet = [[Menulet alloc] init]; -	handleRosterChanged(); +	handleServicesChanged();  }  Slimber::~Slimber() {  	[menulet release];  	delete server;  	delete vCardCollection; +	linkLocalServiceBrowser->stop(); +	delete linkLocalServiceBrowser; +	dnsSDQuerier->stop();  }  void Slimber::handleSelfConnected(bool b) {  	[menulet setSelfConnected: b];  } -void Slimber::handleRosterChanged() { +void Slimber::handleServicesChanged() {  	NSMutableArray* names = [[NSMutableArray alloc] init]; -	boost::shared_ptr<RosterPayload> roster = linkLocalRoster->getRoster(); -	foreach(const RosterItemPayload& item, roster->getItems()) { -		NSString* name = [NSString stringWithUTF8String: item.getName().getUTF8Data()]; -		[names addObject: name]; -		[name release]; +	foreach(const LinkLocalService& service, linkLocalServiceBrowser->getServices()) { +		[names addObject: [NSString stringWithUTF8String: service.getDescription().getUTF8Data()]];  	}  	[menulet setUserNames: names]; diff --git a/Slimber/LinkLocalPresenceManager.cpp b/Slimber/LinkLocalPresenceManager.cpp new file mode 100644 index 0000000..b964786 --- /dev/null +++ b/Slimber/LinkLocalPresenceManager.cpp @@ -0,0 +1,98 @@ +#include "Slimber/LinkLocalPresenceManager.h" + +#include <boost/bind.hpp> + +#include "Swiften/Base/foreach.h" +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" +#include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Elements/Presence.h" + +namespace Swift { + +LinkLocalPresenceManager::LinkLocalPresenceManager(LinkLocalServiceBrowser* browser) : browser(browser) { +	browser->onServiceAdded.connect( +			boost::bind(&LinkLocalPresenceManager::handleServiceAdded, this, _1)); +	browser->onServiceChanged.connect( +			boost::bind(&LinkLocalPresenceManager::handleServiceChanged, this, _1)); +	browser->onServiceRemoved.connect( +			boost::bind(&LinkLocalPresenceManager::handleServiceRemoved, this, _1)); +} + +void LinkLocalPresenceManager::handleServiceAdded(const LinkLocalService& service) { +	boost::shared_ptr<RosterPayload> roster(new RosterPayload()); +	roster->addItem(getRosterItem(service)); +	onRosterChanged(roster); +	onPresenceChanged(getPresence(service)); +} + +void LinkLocalPresenceManager::handleServiceChanged(const LinkLocalService& service) { +	onPresenceChanged(getPresence(service)); +} + +void LinkLocalPresenceManager::handleServiceRemoved(const LinkLocalService& service) { +	boost::shared_ptr<RosterPayload> roster(new RosterPayload()); +	roster->addItem(RosterItemPayload(getJIDForService(service), "", RosterItemPayload::Remove)); +	onRosterChanged(roster); +} + +boost::shared_ptr<RosterPayload> LinkLocalPresenceManager::getRoster() const { +	boost::shared_ptr<RosterPayload> roster(new RosterPayload()); +	foreach(const LinkLocalService& service, browser->getServices()) { +		roster->addItem(getRosterItem(service)); +	} +	return roster; +} + +std::vector<boost::shared_ptr<Presence> > LinkLocalPresenceManager::getAllPresence() const { +	std::vector<boost::shared_ptr<Presence> > result; +	foreach(const LinkLocalService& service, browser->getServices()) { +		result.push_back(getPresence(service)); +	} +	return result; +} + +RosterItemPayload LinkLocalPresenceManager::getRosterItem(const LinkLocalService& service) const { + return RosterItemPayload(getJIDForService(service), getRosterName(service), RosterItemPayload::Both); +} + +String LinkLocalPresenceManager::getRosterName(const LinkLocalService& service) const { +	LinkLocalServiceInfo info = service.getInfo(); +	if (!info.getNick().isEmpty()) { +		return info.getNick(); +	} +	else if (!info.getFirstName().isEmpty()) { +		String result = info.getFirstName(); +		if (!info.getLastName().isEmpty()) { +			result += " " + info.getLastName(); +		} +		return result; +	} +	else if (!info.getLastName().isEmpty()) { +		return info.getLastName(); +	} +	return ""; +} + +JID LinkLocalPresenceManager::getJIDForService(const LinkLocalService& service) const { +	return JID(service.getName()); +} + +boost::shared_ptr<Presence> LinkLocalPresenceManager::getPresence(const LinkLocalService& service) const { +	boost::shared_ptr<Presence> presence(new Presence()); +	presence->setFrom(getJIDForService(service)); +	switch (service.getInfo().getStatus()) { +		case LinkLocalServiceInfo::Available: +			presence->setShow(StatusShow::Online); +			break; +		case LinkLocalServiceInfo::Away: +			presence->setShow(StatusShow::Away); +			break; +		case LinkLocalServiceInfo::DND: +			presence->setShow(StatusShow::DND); +			break; +	} +	presence->setStatus(service.getInfo().getMessage()); +	return presence; +} + +} diff --git a/Slimber/LinkLocalPresenceManager.h b/Slimber/LinkLocalPresenceManager.h new file mode 100644 index 0000000..2af2313 --- /dev/null +++ b/Slimber/LinkLocalPresenceManager.h @@ -0,0 +1,39 @@ +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/signal.hpp> + +#include "Swiften/Elements/RosterItemPayload.h" +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" + +namespace Swift { +	class LinkLocalService; +	class LinkLocalServiceBrowser; +	class RosterPayload; +	class Presence; + +	class LinkLocalPresenceManager { +		public: +			LinkLocalPresenceManager(LinkLocalServiceBrowser*); + +			boost::shared_ptr<RosterPayload> getRoster() const; +			std::vector<boost::shared_ptr<Presence> > getAllPresence() const; + +			boost::signal<void (boost::shared_ptr<RosterPayload>)> onRosterChanged; +			boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChanged; + +		private: +			void handleServiceAdded(const LinkLocalService&); +			void handleServiceChanged(const LinkLocalService&); +			void handleServiceRemoved(const LinkLocalService&); + +			RosterItemPayload getRosterItem(const LinkLocalService& service) const; +			String getRosterName(const LinkLocalService& service) const; +			JID getJIDForService(const LinkLocalService& service) const; +			boost::shared_ptr<Presence> getPresence(const LinkLocalService& service) const; + +		private: +			LinkLocalServiceBrowser* browser; +	}; +} diff --git a/Slimber/Makefile.inc b/Slimber/Makefile.inc index 539646c..16fcb8f 100644 --- a/Slimber/Makefile.inc +++ b/Slimber/Makefile.inc @@ -1,17 +1,16 @@  SLIMBER_TARGET = Slimber/Slimber.a  SLIMBER_SOURCES = \ +	Slimber/LinkLocalPresenceManager.cpp \  	Slimber/FileVCardCollection.cpp \  	Slimber/VCardCollection.cpp \  	Slimber/Server.cpp  SLIMBER_OBJECTS = \  	$(SLIMBER_SOURCES:.cpp=.o) -CLEANFILES += \ -	$(SLIMBER_OBJECTS) \ -	$(SLIMBER_TARGET) -DEPS += \ -	$(SLIMBER_SOURCES:.cpp=.dep) \ +DEPS += $(SLIMBER_SOURCES:.cpp=.dep) +UNITTEST_LIBS += $(SLIMBER_TARGET) +include Slimber/UnitTest/Makefile.inc  include Slimber/CLI/Makefile.inc  ifeq ($(MACOSX),1)  include Slimber/Cocoa/Makefile.inc diff --git a/Slimber/Resources/Credits.html b/Slimber/Resources/Credits.html new file mode 100644 index 0000000..66ecb13 --- /dev/null +++ b/Slimber/Resources/Credits.html @@ -0,0 +1 @@ +<a href="http://swift.im/slimber">http://swift.im/slimber</a> diff --git a/Slimber/Server.cpp b/Slimber/Server.cpp index ba55403..a63201b 100644 --- a/Slimber/Server.cpp +++ b/Slimber/Server.cpp @@ -3,75 +3,89 @@  #include <string>  #include <boost/bind.hpp> +#include "Swiften/LinkLocal/LinkLocalConnector.h" +#include "Swiften/Network/Connection.h" +#include "Swiften/Session/SessionTracer.h" +#include "Swiften/Elements/Element.h" +#include "Swiften/Elements/Presence.h" +#include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Network/BoostConnection.h" +#include "Swiften/Network/BoostConnectionServer.h"  #include "Swiften/Session/SessionTracer.h"  #include "Swiften/Elements/IQ.h"  #include "Swiften/Elements/VCard.h"  #include "Swiften/Server/UserRegistry.h"  #include "Swiften/Base/String.h"  #include "Swiften/LinkLocal/LinkLocalServiceInfo.h" -#include "Swiften/LinkLocal/LinkLocalRoster.h"  #include "Swiften/LinkLocal/OutgoingLinkLocalSession.h"  #include "Swiften/LinkLocal/IncomingLinkLocalSession.h" +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h"  #include "Swiften/Network/ConnectionServer.h"  #include "Slimber/VCardCollection.h" +#include "Slimber/LinkLocalPresenceManager.h"  #include "Swiften/Server/ServerFromClientSession.h"  namespace Swift { -Server::Server(int clientConnectionPort, int linkLocalConnectionPort, boost::shared_ptr<LinkLocalRoster> linkLocalRoster, boost::shared_ptr<DNSSDService> dnsSDService, VCardCollection* vCardCollection) :  -		dnsSDServiceRegistered_(false),  -		rosterRequested_(false),  -		clientConnectionPort_(clientConnectionPort),  -		linkLocalConnectionPort_(linkLocalConnectionPort), -		linkLocalRoster_(linkLocalRoster), -		dnsSDService_(dnsSDService), -		vCardCollection_(vCardCollection) { -	serverFromClientConnectionServer_ =  +Server::Server( +		int clientConnectionPort,  +		int linkLocalConnectionPort,  +		LinkLocalServiceBrowser* linkLocalServiceBrowser, +		VCardCollection* vCardCollection) :  +			linkLocalServiceRegistered(false),  +			rosterRequested(false),  +			clientConnectionPort(clientConnectionPort),  +			linkLocalConnectionPort(linkLocalConnectionPort), +			linkLocalServiceBrowser(linkLocalServiceBrowser), +			vCardCollection(vCardCollection) { +	serverFromClientConnectionServer =   			boost::shared_ptr<BoostConnectionServer>(new BoostConnectionServer( -					clientConnectionPort, &boostIOServiceThread_.getIOService())); -	serverFromClientConnectionServer_->onNewConnection.connect( +					clientConnectionPort, &boostIOServiceThread.getIOService())); +	serverFromClientConnectionServer->onNewConnection.connect(  			boost::bind(&Server::handleNewClientConnection, this, _1)); -	serverFromClientConnectionServer_->start(); - -	serverFromNetworkConnectionServer_ =  -		boost::shared_ptr<BoostConnectionServer>(new BoostConnectionServer( -			linkLocalConnectionPort, &boostIOServiceThread_.getIOService())); -	serverFromNetworkConnectionServer_->onNewConnection.connect( -			boost::bind(&Server::handleNewLinkLocalConnection, this, _1)); -	serverFromNetworkConnectionServer_->start(); +	serverFromClientConnectionServer->start(); -	dnsSDService_->onServiceRegistered.connect -			(boost::bind(&Server::handleServiceRegistered, this, _1)); -	linkLocalRoster_->onRosterChanged.connect( +	presenceManager = new LinkLocalPresenceManager(linkLocalServiceBrowser); +	presenceManager->onRosterChanged.connect(  			boost::bind(&Server::handleRosterChanged, this, _1)); -	linkLocalRoster_->onPresenceChanged.connect( +	presenceManager->onPresenceChanged.connect(  			boost::bind(&Server::handlePresenceChanged, this, _1)); -	dnsSDService_->start(); -} -void Server::handleNewClientConnection(boost::shared_ptr<Connection> c) { -	if (serverFromClientSession_) { -		c->disconnect(); -	} -	serverFromClientSession_ = boost::shared_ptr<ServerFromClientSession>(new ServerFromClientSession(idGenerator_.generateID(), c, &payloadParserFactories_, &payloadSerializers_, &userRegistry_)); -	serverFromClientSession_->onSessionStarted.connect(boost::bind(&Server::handleSessionStarted, this)); -	serverFromClientSession_->onElementReceived.connect(boost::bind(&Server::handleElementReceived, this, _1, serverFromClientSession_)); -	serverFromClientSession_->onSessionFinished.connect(boost::bind(&Server::handleSessionFinished, this, serverFromClientSession_)); -	//tracers_.push_back(boost::shared_ptr<SessionTracer>(new SessionTracer(serverFromClientSession_))); -	serverFromClientSession_->startSession(); +	linkLocalServiceBrowser->onServiceRegistered.connect( +			boost::bind(&Server::handleServiceRegistered, this, _1)); + +	/* +	serverFromNetworkConnectionServer =  +		boost::shared_ptr<BoostConnectionServer>(new BoostConnectionServer( +			linkLocalConnectionPort, &boostIOServiceThread.getIOService())); +	serverFromNetworkConnectionServer->onNewConnection.connect( +			boost::bind(&Server::handleNewLinkLocalConnection, this, _1)); +	serverFromNetworkConnectionServer->start(); +	*/  } -void Server::handleNewLinkLocalConnection(boost::shared_ptr<Connection> connection) { -	boost::shared_ptr<IncomingLinkLocalSession> session( -			new IncomingLinkLocalSession( -				selfJID_, connection,  -				&payloadParserFactories_, &payloadSerializers_)); -	registerLinkLocalSession(session); +Server::~Server() { +	delete presenceManager;  } -void Server::handleServiceRegistered(const DNSSDService::Service& service) { -	std::cout << "Service registered " << service.name << " " << service.type << " " << service.domain << std::endl; -	selfJID_ = JID(service.name); +void Server::handleNewClientConnection(boost::shared_ptr<Connection> connection) { +	if (serverFromClientSession) { +		connection->disconnect(); +	} +	serverFromClientSession = boost::shared_ptr<ServerFromClientSession>( +			new ServerFromClientSession(idGenerator.generateID(), connection,  +					&payloadParserFactories, &payloadSerializers, &userRegistry)); +	serverFromClientSession->onSessionStarted.connect( +			boost::bind(&Server::handleSessionStarted, this)); +	serverFromClientSession->onElementReceived.connect( +			boost::bind(&Server::handleElementReceived, this, _1,  +				serverFromClientSession)); +	serverFromClientSession->onSessionFinished.connect( +			boost::bind(&Server::handleSessionFinished, this,  +			serverFromClientSession)); +	tracers.push_back(boost::shared_ptr<SessionTracer>( +			new SessionTracer(serverFromClientSession))); +	serverFromClientSession->startSession();  }  void Server::handleSessionStarted() { @@ -79,34 +93,18 @@ void Server::handleSessionStarted() {  }  void Server::handleSessionFinished(boost::shared_ptr<ServerFromClientSession>) { -	serverFromClientSession_.reset(); +	serverFromClientSession.reset();  	unregisterService(); -	selfJID_ = JID(); -	rosterRequested_ = false; +	selfJID = JID(); +	rosterRequested = false;  	onSelfConnected(false); -	lastPresence_.reset(); -} - -void Server::handleLinkLocalSessionFinished(boost::shared_ptr<Session> session) { -	std::cout << "Link local session from " << session->getRemoteJID() << " ended" << std::endl; -	linkLocalSessions_.erase(std::remove(linkLocalSessions_.begin(), linkLocalSessions_.end(), session), linkLocalSessions_.end()); -} - -void Server::handleLinkLocalElementReceived(boost::shared_ptr<Element> element, boost::shared_ptr<Session> session) { -	if (boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element)) { -		JID fromJID = session->getRemoteJID(); -		if (!linkLocalRoster_->hasItem(fromJID)) { -			return; // TODO: Queue -		} -		stanza->setFrom(fromJID); -		serverFromClientSession_->sendElement(stanza); -	} +	lastPresence.reset();  }  void Server::unregisterService() { -	if (dnsSDServiceRegistered_) { -		dnsSDServiceRegistered_ = false; -		dnsSDService_->unregisterService(); +	if (linkLocalServiceRegistered) { +		linkLocalServiceRegistered = false; +		linkLocalServiceBrowser->unregisterService();  	}  } @@ -123,14 +121,17 @@ void Server::handleElementReceived(boost::shared_ptr<Element> element, boost::sh  	if (boost::shared_ptr<Presence> presence = boost::dynamic_pointer_cast<Presence>(stanza)) {  		if (presence->getType() == Presence::Available) { -			if (!dnsSDServiceRegistered_) { -				dnsSDServiceRegistered_ = true; -				dnsSDService_->registerService(session->getRemoteJID().toBare().toString(), linkLocalConnectionPort_, getLinkLocalServiceInfo(presence)); +			if (!linkLocalServiceRegistered) { +				linkLocalServiceRegistered = true; +				linkLocalServiceBrowser->registerService( +						session->getRemoteJID().toBare().toString(),  +						linkLocalConnectionPort, getLinkLocalServiceInfo(presence));  			}  			else { -				dnsSDService_->updateService(getLinkLocalServiceInfo(presence)); +				linkLocalServiceBrowser->updateService( +						getLinkLocalServiceInfo(presence));  			} -			lastPresence_ = presence; +			lastPresence = presence;  		}  		else {  			unregisterService(); @@ -140,9 +141,9 @@ void Server::handleElementReceived(boost::shared_ptr<Element> element, boost::sh  		if (boost::shared_ptr<IQ> iq = boost::dynamic_pointer_cast<IQ>(stanza)) {  			if (iq->getPayload<RosterPayload>()) {  				if (iq->getType() == IQ::Get) { -					session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), linkLocalRoster_->getRoster())); -					rosterRequested_ = true; -					foreach(const boost::shared_ptr<Presence> presence, linkLocalRoster_->getAllPresence()) { +					session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), presenceManager->getRoster())); +					rosterRequested = true; +					foreach(const boost::shared_ptr<Presence> presence, presenceManager->getAllPresence()) {  						session->sendElement(presence);  					}  				} @@ -152,13 +153,13 @@ void Server::handleElementReceived(boost::shared_ptr<Element> element, boost::sh  			}  			if (boost::shared_ptr<VCard> vcard = iq->getPayload<VCard>()) {  				if (iq->getType() == IQ::Get) { -					session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), vCardCollection_->getOwnVCard())); +					session->sendElement(IQ::createResult(iq->getFrom(), iq->getID(), vCardCollection->getOwnVCard()));  				}  				else { -					vCardCollection_->setOwnVCard(vcard); +					vCardCollection->setOwnVCard(vcard);  					session->sendElement(IQ::createResult(iq->getFrom(), iq->getID())); -					if (lastPresence_) { -						dnsSDService_->updateService(getLinkLocalServiceInfo(lastPresence_)); +					if (lastPresence) { +						linkLocalServiceBrowser->updateService(getLinkLocalServiceInfo(lastPresence));  					}  				}  			} @@ -167,6 +168,7 @@ void Server::handleElementReceived(boost::shared_ptr<Element> element, boost::sh  			}  		}  	} +	/*  	else {  		JID toJID = stanza->getTo();  		boost::shared_ptr<Session> outgoingSession =  @@ -175,17 +177,17 @@ void Server::handleElementReceived(boost::shared_ptr<Element> element, boost::sh  			outgoingSession->sendElement(stanza);  		}  		else { -			if (linkLocalRoster_->hasItem(toJID)) { +			if (linkLocalServiceBrowser->hasItem(toJID)) {  				boost::shared_ptr<LinkLocalConnector> connector =  					getLinkLocalConnectorForJID(toJID);  				if (!connector) {  					connector = boost::shared_ptr<LinkLocalConnector>(  							new LinkLocalConnector(  								toJID,  -								linkLocalRoster_->getHostname(toJID),  -								linkLocalRoster_->getPort(toJID),  -								dnsSDService_, -								boost::shared_ptr<BoostConnection>(new BoostConnection(&boostIOServiceThread_.getIOService())))); +								linkLocalServiceBrowser->getHostname(toJID),  +								linkLocalServiceBrowser->getPort(toJID),  +								linkLocalServiceBrowser, +								boost::shared_ptr<BoostConnection>(new BoostConnection(&boostIOServiceThread.getIOService()))));  					connector->onConnectFinished.connect(  							boost::bind(&Server::handleConnectFinished, this, connector, _1));  					connectors_.push_back(connector); @@ -200,6 +202,32 @@ void Server::handleElementReceived(boost::shared_ptr<Element> element, boost::sh  			}  		}  	} +	*/ +} + +/* +void Server::handleNewLinkLocalConnection(boost::shared_ptr<Connection> connection) { +	boost::shared_ptr<IncomingLinkLocalSession> session( +			new IncomingLinkLocalSession( +				selfJID, connection,  +				&payloadParserFactories, &payloadSerializers)); +	registerLinkLocalSession(session); +} + +void Server::handleLinkLocalSessionFinished(boost::shared_ptr<Session> session) { +	std::cout << "Link local session from " << session->getRemoteJID() << " ended" << std::endl; +	linkLocalSessions_.erase(std::remove(linkLocalSessions_.begin(), linkLocalSessions_.end(), session), linkLocalSessions_.end()); +} + +void Server::handleLinkLocalElementReceived(boost::shared_ptr<Element> element, boost::shared_ptr<Session> session) { +	if (boost::shared_ptr<Stanza> stanza = boost::dynamic_pointer_cast<Stanza>(element)) { +		JID fromJID = session->getRemoteJID(); +		if (!linkLocalServiceBrowser->hasItem(fromJID)) { +			return; // TODO: Queue +		} +		stanza->setFrom(fromJID); +		serverFromClientSession->sendElement(stanza); +	}  }  void Server::handleConnectFinished(boost::shared_ptr<LinkLocalConnector> connector, bool error) { @@ -210,8 +238,8 @@ void Server::handleConnectFinished(boost::shared_ptr<LinkLocalConnector> connect  	else {  		boost::shared_ptr<OutgoingLinkLocalSession> outgoingSession(  				new OutgoingLinkLocalSession( -					selfJID_, connector->getRemoteJID(), connector->getConnection(), -					&payloadParserFactories_, &payloadSerializers_)); +					selfJID, connector->getRemoteJID(), connector->getConnection(), +					&payloadParserFactories, &payloadSerializers));  		foreach(const boost::shared_ptr<Element> element, connector->getQueuedElements()) {  			outgoingSession->queueElement(element);  		} @@ -225,7 +253,7 @@ void Server::registerLinkLocalSession(boost::shared_ptr<Session> session) {  	session->onSessionFinished.connect(boost::bind(&Server::handleLinkLocalSessionFinished, this, session));  	session->onElementReceived.connect(boost::bind(&Server::handleLinkLocalElementReceived, this, _1, session));  	linkLocalSessions_.push_back(session); -	//tracers_.push_back(boost::shared_ptr<SessionTracer>(new SessionTracer(session))); +	//tracers.push_back(boost::shared_ptr<SessionTracer>(new SessionTracer(session)));  	session->startSession();  } @@ -246,24 +274,32 @@ boost::shared_ptr<LinkLocalConnector> Server::getLinkLocalConnectorForJID(const  	}  	return boost::shared_ptr<LinkLocalConnector>();  } +*/ + +void Server::handleServiceRegistered(const DNSSDServiceID& service) { +	selfJID = JID(service.getName()); +}  void Server::handleRosterChanged(boost::shared_ptr<RosterPayload> roster) { -	if (rosterRequested_) { -		boost::shared_ptr<IQ> iq = IQ::createRequest(IQ::Set, serverFromClientSession_->getRemoteJID(), idGenerator_.generateID(), roster); -		iq->setFrom(serverFromClientSession_->getRemoteJID().toBare()); -		serverFromClientSession_->sendElement(iq); +	if (rosterRequested) { +		assert(serverFromClientSession); +		boost::shared_ptr<IQ> iq = IQ::createRequest( +				IQ::Set, serverFromClientSession->getRemoteJID(),  +				idGenerator.generateID(), roster); +		iq->setFrom(serverFromClientSession->getRemoteJID().toBare()); +		serverFromClientSession->sendElement(iq);  	}  }  void Server::handlePresenceChanged(boost::shared_ptr<Presence> presence) { -	if (rosterRequested_) { -		serverFromClientSession_->sendElement(presence); +	if (rosterRequested) { +		serverFromClientSession->sendElement(presence);  	}  }  LinkLocalServiceInfo Server::getLinkLocalServiceInfo(boost::shared_ptr<Presence> presence) {  	LinkLocalServiceInfo info; -	boost::shared_ptr<VCard> vcard = vCardCollection_->getOwnVCard(); +	boost::shared_ptr<VCard> vcard = vCardCollection->getOwnVCard();  	if (!vcard->getFamilyName().isEmpty() || !vcard->getGivenName().isEmpty()) {  		info.setFirstName(vcard->getGivenName());  		info.setLastName(vcard->getFamilyName()); @@ -294,7 +330,7 @@ LinkLocalServiceInfo Server::getLinkLocalServiceInfo(boost::shared_ptr<Presence>  			info.setStatus(LinkLocalServiceInfo::DND);  			break;  	} -	info.setPort(linkLocalConnectionPort_); +	info.setPort(linkLocalConnectionPort);  	return info;  } diff --git a/Slimber/Server.h b/Slimber/Server.h index ac80509..3ed0a58 100644 --- a/Slimber/Server.h +++ b/Slimber/Server.h @@ -3,49 +3,56 @@  #include <boost/shared_ptr.hpp>  #include <vector> -#include "Swiften/Network/BoostConnection.h"  #include "Swiften/Network/BoostIOServiceThread.h" -#include "Swiften/Network/BoostConnectionServer.h"  #include "Swiften/Server/UserRegistry.h"  #include "Swiften/Base/IDGenerator.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/LinkLocal/DNSSDService.h" -#include "Swiften/LinkLocal/LinkLocalRoster.h" -#include "Swiften/Session/SessionTracer.h"  #include "Swiften/Server/ServerFromClientSession.h" -#include "Swiften/Elements/Element.h" -#include "Swiften/LinkLocal/LinkLocalConnector.h"  #include "Swiften/JID/JID.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/RosterPayload.h"  #include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h"  #include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h"  namespace Swift { +	class DNSSDServiceID; +	class String;  	class VCardCollection; +	class LinkLocalServiceBrowser; +	class LinkLocalPresenceManager; +	class BoostConnectionServer; +	class SessionTracer; +	class RosterPayload; +	class Presence;  	class Server {  		public: -			Server(int clientConnectionPort, int linkLocalConnectionPort, boost::shared_ptr<LinkLocalRoster>, boost::shared_ptr<DNSSDService> dnsSDService, VCardCollection* vCardCollection); +			Server( +					int clientConnectionPort,  +					int linkLocalConnectionPort,  +					LinkLocalServiceBrowser* browser,  +					VCardCollection* vCardCollection); +			~Server();  			boost::signal<void (bool)> onSelfConnected;  		private:  			void handleNewClientConnection(boost::shared_ptr<Connection> c); -			void handleNewLinkLocalConnection(boost::shared_ptr<Connection> connection); -			void handleServiceRegistered(const DNSSDService::Service& service);  			void handleSessionStarted();  			void handleSessionFinished(boost::shared_ptr<ServerFromClientSession>); +			void handleElementReceived(boost::shared_ptr<Element> element, boost::shared_ptr<ServerFromClientSession> session); +			void handleRosterChanged(boost::shared_ptr<RosterPayload> roster); +			void handlePresenceChanged(boost::shared_ptr<Presence> presence); +			void handleServiceRegistered(const DNSSDServiceID& service); +/* +			void handleNewLinkLocalConnection(boost::shared_ptr<Connection> connection);  			void handleLinkLocalSessionFinished(boost::shared_ptr<Session> session);  			void handleLinkLocalElementReceived(boost::shared_ptr<Element> element, boost::shared_ptr<Session> session); -			void unregisterService(); -			void handleElementReceived(boost::shared_ptr<Element> element, boost::shared_ptr<ServerFromClientSession> session);  			void handleConnectFinished(boost::shared_ptr<LinkLocalConnector> connector, bool error);  			void registerLinkLocalSession(boost::shared_ptr<Session> session);  			boost::shared_ptr<Session> getLinkLocalSessionForJID(const JID& jid);  			boost::shared_ptr<LinkLocalConnector> getLinkLocalConnectorForJID(const JID& jid); -			void handleRosterChanged(boost::shared_ptr<RosterPayload> roster); -			void handlePresenceChanged(boost::shared_ptr<Presence> presence); +			*/ + +			void unregisterService();  			LinkLocalServiceInfo getLinkLocalServiceInfo(boost::shared_ptr<Presence> presence);  		private: @@ -59,25 +66,27 @@ namespace Swift {  			};  		private: -			IDGenerator idGenerator_; -			BoostIOServiceThread boostIOServiceThread_; -			DummyUserRegistry userRegistry_; -			bool dnsSDServiceRegistered_; -			bool rosterRequested_; -			int clientConnectionPort_; -			int linkLocalConnectionPort_; -			boost::shared_ptr<LinkLocalRoster> linkLocalRoster_; -			boost::shared_ptr<DNSSDService> dnsSDService_; -			VCardCollection* vCardCollection_; -			boost::shared_ptr<Presence> lastPresence_; -			boost::shared_ptr<BoostConnectionServer> serverFromClientConnectionServer_; -			boost::shared_ptr<ServerFromClientSession> serverFromClientSession_; +			IDGenerator idGenerator; +			FullPayloadParserFactoryCollection payloadParserFactories; +			FullPayloadSerializerCollection payloadSerializers; +			BoostIOServiceThread boostIOServiceThread; +			DummyUserRegistry userRegistry; +			bool linkLocalServiceRegistered; +			bool rosterRequested; +			int clientConnectionPort; +			int linkLocalConnectionPort; +			LinkLocalServiceBrowser* linkLocalServiceBrowser; +			VCardCollection* vCardCollection; +			LinkLocalPresenceManager* presenceManager; +			boost::shared_ptr<BoostConnectionServer> serverFromClientConnectionServer; +			boost::shared_ptr<ServerFromClientSession> serverFromClientSession; +			boost::shared_ptr<Presence> lastPresence; +			JID selfJID; +			/*  			boost::shared_ptr<BoostConnectionServer> serverFromNetworkConnectionServer_; -			std::vector< boost::shared_ptr<SessionTracer> > tracers_;  			std::vector< boost::shared_ptr<Session> > linkLocalSessions_;  			std::vector< boost::shared_ptr<LinkLocalConnector> > connectors_; -			FullPayloadParserFactoryCollection payloadParserFactories_; -			FullPayloadSerializerCollection payloadSerializers_; -			JID selfJID_; +*/ +			std::vector< boost::shared_ptr<SessionTracer> > tracers;  	};  } diff --git a/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp b/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp new file mode 100644 index 0000000..f15daf4 --- /dev/null +++ b/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp @@ -0,0 +1,232 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/bind.hpp> +#include <map> + +#include "Swiften/Elements/Presence.h" +#include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Elements/RosterItemPayload.h" +#include "Slimber/LinkLocalPresenceManager.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" +#include "Swiften/EventLoop/DummyEventLoop.h" + +using namespace Swift; + +class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(LinkLocalPresenceManagerTest); +		CPPUNIT_TEST(testConstructor); +		CPPUNIT_TEST(testServiceAdded); +		CPPUNIT_TEST(testServiceRemoved); +		CPPUNIT_TEST(testServiceChanged); +		CPPUNIT_TEST(testGetRoster); +		CPPUNIT_TEST(testGetAllPresence); +		CPPUNIT_TEST(testGetRoster_InfoWithNick); +		CPPUNIT_TEST(testGetRoster_InfoWithFirstName); +		CPPUNIT_TEST(testGetRoster_InfoWithLastName); +		CPPUNIT_TEST(testGetRoster_InfoWithFirstAndLastName); +		CPPUNIT_TEST(testGetRoster_NoInfo); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		void setUp() { +			eventLoop = new DummyEventLoop(); +			querier = boost::shared_ptr<FakeDNSSDQuerier>(new FakeDNSSDQuerier("wonderland.lit")); +			browser = new LinkLocalServiceBrowser(querier); +			browser->start(); +		} + +		void tearDown() { +			browser->stop(); +			delete browser; +			delete eventLoop; +		} + +		void testConstructor() { +			addService("alice@wonderland"); +			addService("rabbit@teaparty"); +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(testling->getRoster()->getItems().size())); +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(testling->getAllPresence().size())); +		} + +		void testServiceAdded() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland", "Alice"); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(rosterChanges.size())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(rosterChanges[0]->getItems().size())); +			boost::optional<RosterItemPayload> item = rosterChanges[0]->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT(item); +			CPPUNIT_ASSERT_EQUAL(String("Alice"), item->getName()); +			CPPUNIT_ASSERT_EQUAL(RosterItemPayload::Both, item->getSubscription()); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(presenceChanges.size())); +			CPPUNIT_ASSERT(StatusShow::Online == presenceChanges[0]->getShow()); +			CPPUNIT_ASSERT(JID("alice@wonderland") == presenceChanges[0]->getFrom()); +		} + +		void testServiceRemoved() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland"); +			removeService("alice@wonderland"); + +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(rosterChanges.size())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(rosterChanges[1]->getItems().size())); +			boost::optional<RosterItemPayload> item = rosterChanges[1]->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT(item); +			CPPUNIT_ASSERT_EQUAL(RosterItemPayload::Remove, item->getSubscription()); +		} + +		void testServiceChanged() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland"); +			updateServicePresence("alice@wonderland", LinkLocalServiceInfo::Away, "I'm Away"); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(rosterChanges.size())); +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(presenceChanges.size())); +			CPPUNIT_ASSERT(StatusShow::Away == presenceChanges[1]->getShow()); +			CPPUNIT_ASSERT(JID("alice@wonderland") == presenceChanges[1]->getFrom()); +			CPPUNIT_ASSERT_EQUAL(String("I'm Away"), presenceChanges[1]->getStatus()); +		} + +		void testGetAllPresence() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland"); +			addService("rabbit@teaparty"); +			updateServicePresence("rabbit@teaparty", LinkLocalServiceInfo::Away, "Partying"); +			 +			std::vector<boost::shared_ptr<Presence> > presences = testling->getAllPresence(); +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(presences.size())); +			// The order doesn't matter +			CPPUNIT_ASSERT(JID("rabbit@teaparty") == presences[0]->getFrom()); +			CPPUNIT_ASSERT(StatusShow::Away == presences[0]->getShow()); +			CPPUNIT_ASSERT(JID("alice@wonderland") == presences[1]->getFrom()); +			CPPUNIT_ASSERT(StatusShow::Online == presences[1]->getShow()); +		} + +		void testGetRoster() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland", "Alice"); +			addService("rabbit@teaparty", "Rabbit"); + +			boost::shared_ptr<RosterPayload> roster = testling->getRoster(); +			CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(roster->getItems().size())); +			boost::optional<RosterItemPayload> item; +			item = roster->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT(item); +			CPPUNIT_ASSERT_EQUAL(String("Alice"), item->getName()); +			CPPUNIT_ASSERT_EQUAL(RosterItemPayload::Both, item->getSubscription()); +			item = roster->getItem(JID("rabbit@teaparty")); +			CPPUNIT_ASSERT(item); +			CPPUNIT_ASSERT_EQUAL(String("Rabbit"), item->getName()); +			CPPUNIT_ASSERT_EQUAL(RosterItemPayload::Both, item->getSubscription()); +		} + +		void testGetRoster_InfoWithNick() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland", "Alice", "Alice In", "Wonderland"); + +			boost::optional<RosterItemPayload> item = testling->getRoster()->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT_EQUAL(String("Alice"), item->getName()); +		} + +		void testGetRoster_InfoWithFirstName() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland", "", "Alice In", ""); + +			boost::optional<RosterItemPayload> item = testling->getRoster()->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT_EQUAL(String("Alice In"), item->getName()); +		} + +		void testGetRoster_InfoWithLastName() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland", "", "", "Wonderland"); + +			boost::optional<RosterItemPayload> item = testling->getRoster()->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT_EQUAL(String("Wonderland"), item->getName()); +		} + +		void testGetRoster_InfoWithFirstAndLastName() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland", "", "Alice In", "Wonderland"); + +			boost::optional<RosterItemPayload> item = testling->getRoster()->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT_EQUAL(String("Alice In Wonderland"), item->getName()); +		} + +		void testGetRoster_NoInfo() { +			std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + +			addService("alice@wonderland"); + +			boost::optional<RosterItemPayload> item = testling->getRoster()->getItem(JID("alice@wonderland")); +			CPPUNIT_ASSERT_EQUAL(String(""), item->getName()); +		} + +	private: +		std::auto_ptr<LinkLocalPresenceManager> createTestling() { +			std::auto_ptr<LinkLocalPresenceManager> testling( +					new LinkLocalPresenceManager(browser)); +			testling->onRosterChanged.connect(boost::bind( +					&LinkLocalPresenceManagerTest::handleRosterChanged, this, _1)); +			testling->onPresenceChanged.connect(boost::bind( +					&LinkLocalPresenceManagerTest::handlePresenceChanged, this, _1)); +			return testling; +		} + +		void addService(const String& name, const String& nickName = String(), const String& firstName = String(), const String& lastName = String()) { +			DNSSDServiceID service(name, "local."); +			LinkLocalServiceInfo info; +			info.setFirstName(firstName); +			info.setLastName(lastName); +			info.setNick(nickName); +			querier->setServiceInfo(service, DNSSDResolveServiceQuery::Result(name + "._presence._tcp.local", "rabbithole.local", 1234, info.toTXTRecord())); +			querier->addService(service); +			eventLoop->processEvents(); +		} + +		void removeService(const String& name) { +			DNSSDServiceID service(name, "local."); +			querier->removeService(DNSSDServiceID(name, "local.")); +			eventLoop->processEvents(); +		} + +		void updateServicePresence(const String& name, LinkLocalServiceInfo::Status status, const String& message) { +			DNSSDServiceID service(name, "local."); +			LinkLocalServiceInfo info; +			info.setStatus(status); +			info.setMessage(message); +			querier->setServiceInfo(service, DNSSDResolveServiceQuery::Result(name + "._presence._tcp.local", "rabbithole.local", 1234, info.toTXTRecord())); +			eventLoop->processEvents(); +		} + +		void handleRosterChanged(boost::shared_ptr<RosterPayload> payload) { +			rosterChanges.push_back(payload); +		} + +		void handlePresenceChanged(boost::shared_ptr<Presence> presence) { +			presenceChanges.push_back(presence); +		} + +	private: +		DummyEventLoop* eventLoop; +		boost::shared_ptr<FakeDNSSDQuerier> querier; +		LinkLocalServiceBrowser* browser; +		std::vector< boost::shared_ptr<RosterPayload> > rosterChanges; +		std::vector< boost::shared_ptr<Presence> > presenceChanges; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalPresenceManagerTest); diff --git a/Slimber/UnitTest/Makefile.inc b/Slimber/UnitTest/Makefile.inc new file mode 100644 index 0000000..f2c4db8 --- /dev/null +++ b/Slimber/UnitTest/Makefile.inc @@ -0,0 +1,2 @@ +UNITTEST_SOURCES += \ +	Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp diff --git a/Swift/Controllers/Makefile.inc b/Swift/Controllers/Makefile.inc index 4c69e34..b145c54 100644 --- a/Swift/Controllers/Makefile.inc +++ b/Swift/Controllers/Makefile.inc @@ -18,7 +18,6 @@ SWIFT_CONTROLLERS_OBJECTS = \  TARGETS += $(SWIFT_CONTROLLERS_TARGET)  UNITTEST_LIBS += $(SWIFT_CONTROLLERS_TARGET) -CLEANFILES += $(SWIFT_CONTROLLERS_TARGET) $(SWIFT_CONTROLLERS_OBJECTS)  DEPS += $(SWIFT_CONTROLLERS_SOURCES:.cpp=.dep)  $(SWIFT_CONTROLLERS_TARGET): $(SWIFT_CONTROLLERS_OBJECTS) diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index a91216c..bb10cfd 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -38,7 +38,7 @@ using namespace Swift;  class ClientSessionTest : public CppUnit::TestFixture {  		CPPUNIT_TEST_SUITE(ClientSessionTest); -		//CPPUNIT_TEST(testConstructor); +		CPPUNIT_TEST(testConstructor);  		/*  		CPPUNIT_TEST(testStart_Error);  		CPPUNIT_TEST(testStart_XMLError); diff --git a/Swiften/Elements/RosterPayload.cpp b/Swiften/Elements/RosterPayload.cpp index 6d39264..8e2fd87 100644 --- a/Swiften/Elements/RosterPayload.cpp +++ b/Swiften/Elements/RosterPayload.cpp @@ -7,7 +7,7 @@ boost::optional<RosterItemPayload> RosterPayload::getItem(const JID& jid) const  	foreach(const RosterItemPayload& item, items_) {      // FIXME: MSVC rejects this. Find out why.  		//if (item.getJID() == jid) { -    if (item.getJID().compare(jid, JID::WithResource)) { +    if (item.getJID().equals(jid, JID::WithResource)) {  			return boost::optional<RosterItemPayload>(item);  		}  	} diff --git a/Swiften/Examples/EchoBot/Makefile.inc b/Swiften/Examples/EchoBot/Makefile.inc index 09c63d5..beab023 100644 --- a/Swiften/Examples/EchoBot/Makefile.inc +++ b/Swiften/Examples/EchoBot/Makefile.inc @@ -4,7 +4,7 @@ ECHOBOT_SOURCES += \  ECHOBOT_OBJECTS = \  	$(ECHOBOT_SOURCES:.cpp=.o) -CLEANFILES += $(ECHOBOT_OBJECTS) $(ECHOBOT_TARGET) +CLEANFILES += $(ECHOBOT_TARGET)  DEPS += $(ECHOBOT_SOURCES:.cpp=.dep)  EXAMPLES_TARGETS += $(ECHOBOT_TARGET) diff --git a/Swiften/LinkLocal/AppleDNSSDService.cpp b/Swiften/LinkLocal/AppleDNSSDService.cpp deleted file mode 100644 index 969cbb2..0000000 --- a/Swiften/LinkLocal/AppleDNSSDService.cpp +++ /dev/null @@ -1,301 +0,0 @@ -#include "Swiften/LinkLocal/AppleDNSSDService.h" - -#include <algorithm> -#include <unistd.h> -#include <iostream> -#include <sys/socket.h> -#include <netinet/in.h> -#include <fcntl.h> - -#include "Swiften/EventLoop/MainEventLoop.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" -#include "Swiften/Network/HostAddress.h" - -namespace Swift { - -AppleDNSSDService::AppleDNSSDService() : thread(0), stopRequested(false), haveError(false), browseSDRef(0), registerSDRef(0) { -	int fds[2]; -	int result = pipe(fds); -	assert(result == 0); -	interruptSelectReadSocket = fds[0]; -	fcntl(interruptSelectReadSocket, F_SETFL, fcntl(interruptSelectReadSocket, F_GETFL)|O_NONBLOCK); -	interruptSelectWriteSocket = fds[1]; -} - -AppleDNSSDService::~AppleDNSSDService() { -	stop(); -} - -void AppleDNSSDService::start() { -	stop(); -	thread = new boost::thread(boost::bind(&AppleDNSSDService::doStart, shared_from_this())); -} - -void AppleDNSSDService::stop() { -	if (thread) { -		stopRequested = true; -		interruptSelect(); -		thread->join(); -		delete thread; -		stopRequested = false; -	} -} - -void AppleDNSSDService::registerService(const String& name, int port, const LinkLocalServiceInfo& info) { -	boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -	assert(!registerSDRef); -	ByteArray txtRecord = info.toTXTRecord(); -	DNSServiceErrorType result = DNSServiceRegister(®isterSDRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port, txtRecord.getSize(), txtRecord.getData(), &AppleDNSSDService::handleServiceRegisteredGlobal, this); -	if (result != kDNSServiceErr_NoError) { -		std::cerr << "Error creating service registration" << std::endl; -		haveError = true; -	} - -	interruptSelect(); -} - -void AppleDNSSDService::updateService(const LinkLocalServiceInfo& info) { -	boost::lock_guard<boost::mutex> lock(sdRefsMutex); -	assert(registerSDRef); -	ByteArray txtRecord = info.toTXTRecord(); -	DNSServiceUpdateRecord(registerSDRef, NULL, NULL, txtRecord.getSize(), txtRecord.getData(), 0); -} - -void AppleDNSSDService::unregisterService() { -	boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -	assert(registerSDRef); -	DNSServiceRefDeallocate(registerSDRef); // Interrupts select() -	registerSDRef = NULL; -} - -void AppleDNSSDService::startResolvingService(const Service& service) { -	boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -	DNSServiceRef resolveSDRef; -	DNSServiceErrorType result = DNSServiceResolve(&resolveSDRef, 0, service.networkInterface, service.name.getUTF8Data(), service.type.getUTF8Data(), service.domain.getUTF8Data(), &AppleDNSSDService::handleServiceResolvedGlobal, this); -	if (result != kDNSServiceErr_NoError) { -		std::cerr << "Error creating service resolve query" << std::endl; -		haveError = true; -	} -	else { -		bool isNew = resolveSDRefs.insert(std::make_pair(service, resolveSDRef)).second; -		assert(isNew); -	} - -	interruptSelect(); -} - -void AppleDNSSDService::stopResolvingService(const Service& service) { -	boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -	ServiceSDRefMap::iterator i = resolveSDRefs.find(service); -	assert(i != resolveSDRefs.end()); -	DNSServiceRefDeallocate(i->second); // Interrupts select() -	resolveSDRefs.erase(i); -} - -void AppleDNSSDService::resolveHostname(const String& hostname, int interfaceIndex) { -	boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -	DNSServiceRef hostnameResolveSDRef; -	DNSServiceErrorType result = DNSServiceGetAddrInfo(&hostnameResolveSDRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4, hostname.getUTF8Data(), &AppleDNSSDService::handleHostnameResolvedGlobal, this); -	if (result != kDNSServiceErr_NoError) { -		std::cerr << "Error creating hostname resolve query" << std::endl; -		haveError = true; -	} -	else { -		hostnameResolveSDRefs.push_back(hostnameResolveSDRef); -	} - -	interruptSelect(); -} - -void AppleDNSSDService::doStart() { -	haveError = false; -	onStarted(); - -	// Listen for new services -	{ -		boost::lock_guard<boost::mutex> lock(sdRefsMutex); -		assert(!browseSDRef); -		DNSServiceErrorType result = DNSServiceBrowse(&browseSDRef, 0, 0, "_presence._tcp", 0, &AppleDNSSDService::handleServiceDiscoveredGlobal , this); -		if (result != kDNSServiceErr_NoError) { -			std::cerr << "Error creating browse query" << std::endl; -			haveError = true; -		} -	} - -	// Run the main loop -	while (!haveError && !stopRequested) { -		fd_set fdSet; -		FD_ZERO(&fdSet); -		int maxSocket = interruptSelectReadSocket; -		FD_SET(interruptSelectReadSocket, &fdSet); - -		{ -			boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -			// Browsing -			int browseSocket = DNSServiceRefSockFD(browseSDRef); -			maxSocket = std::max(maxSocket, browseSocket); -			FD_SET(browseSocket, &fdSet); - -			// Registration -			if (registerSDRef) { -				int registerSocket = DNSServiceRefSockFD(registerSDRef); -				maxSocket = std::max(maxSocket, registerSocket); -				FD_SET(registerSocket, &fdSet); -			} - -			// Service resolving -			for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { -				int resolveSocket = DNSServiceRefSockFD(i->second); -				maxSocket = std::max(maxSocket, resolveSocket); -				FD_SET(resolveSocket, &fdSet); -			} - -			// Hostname resolving -			for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) { -				int hostnameResolveSocket = DNSServiceRefSockFD(*i); -				maxSocket = std::max(maxSocket, hostnameResolveSocket); -				FD_SET(hostnameResolveSocket, &fdSet); -			} -		} - -		int selectResult = select(maxSocket+1, &fdSet, NULL, NULL, 0); - -		// Flush the interruptSelectReadSocket -		if (FD_ISSET(interruptSelectReadSocket, &fdSet)) { -			char dummy; -			while (read(interruptSelectReadSocket, &dummy, 1) > 0) {} -		} - -		{ -			boost::lock_guard<boost::mutex> lock(sdRefsMutex); -			if (selectResult <= 0) { -				continue; -			} -			if (FD_ISSET(DNSServiceRefSockFD(browseSDRef), &fdSet)) { -				DNSServiceProcessResult(browseSDRef); -			} -			if (registerSDRef && FD_ISSET(DNSServiceRefSockFD(registerSDRef), &fdSet)) { -				DNSServiceProcessResult(registerSDRef); -			} -			for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { -				if (FD_ISSET(DNSServiceRefSockFD(i->second), &fdSet)) { -					DNSServiceProcessResult(i->second); -				} -			} -			for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) { -				if (FD_ISSET(DNSServiceRefSockFD(*i), &fdSet)) { -					DNSServiceProcessResult(*i); -					hostnameResolveSDRefs.erase(std::remove(hostnameResolveSDRefs.begin(), hostnameResolveSDRefs.end(), *i), hostnameResolveSDRefs.end()); -					DNSServiceRefDeallocate(*i); -					break; // Stop the loop, because we removed an element -				} -			} -		} -	} - -	{ -		boost::lock_guard<boost::mutex> lock(sdRefsMutex); - -		for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { -			DNSServiceRefDeallocate(i->second); -		} -		resolveSDRefs.clear(); - -		for (HostnameSDRefs::const_iterator i = hostnameResolveSDRefs.begin(); i != hostnameResolveSDRefs.end(); ++i) { -			DNSServiceRefDeallocate(*i); -		} -		hostnameResolveSDRefs.clear(); - -		if (registerSDRef) { -			DNSServiceRefDeallocate(registerSDRef); -			registerSDRef = NULL; -		} - -		DNSServiceRefDeallocate(browseSDRef); -		browseSDRef = NULL; -	} - -	MainEventLoop::postEvent(boost::bind(boost::ref(onStopped), haveError), shared_from_this()); -} - -void AppleDNSSDService::interruptSelect() { -	char c = 0; -	write(interruptSelectWriteSocket, &c, 1); -} - -void AppleDNSSDService::handleServiceDiscoveredGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context ) { -	static_cast<AppleDNSSDService*>(context)->handleServiceDiscovered(sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain); -} - -void AppleDNSSDService::handleServiceDiscovered(DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain) { -	if (errorCode != kDNSServiceErr_NoError) { -		return; -	} -	else { -		Service service(serviceName, regtype, replyDomain, interfaceIndex); -		if (flags & kDNSServiceFlagsAdd) { -			MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); -		} -		else { -			MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); -		} -	} -} - -void AppleDNSSDService::handleServiceRegisteredGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { -	static_cast<AppleDNSSDService*>(context)->handleServiceRegistered(sdRef, flags, errorCode, name, regtype, domain); -} - -void AppleDNSSDService::handleServiceRegistered(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) { -	if (errorCode != kDNSServiceErr_NoError) { -		std::cerr << "Error registering service" << std::endl; -		haveError = true; -	} -	else { -		MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRegistered), Service(name, regtype, domain, 0)), shared_from_this()); -	} -} - -void AppleDNSSDService::handleServiceResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context ) { -	static_cast<AppleDNSSDService*>(context)->handleServiceResolved(sdRef, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtLen, txtRecord); -} - -void AppleDNSSDService::handleServiceResolved(DNSServiceRef sdRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord) { -	if (errorCode != kDNSServiceErr_NoError) { -		// TODO -		std::cerr << "Resolve error " << hosttarget << std::endl; -		return; -	} -	for (ServiceSDRefMap::const_iterator i = resolveSDRefs.begin(); i != resolveSDRefs.end(); ++i) { -		if (i->second == sdRef) { -			MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), i->first, ResolveResult(hosttarget, port, LinkLocalServiceInfo::createFromTXTRecord(ByteArray(reinterpret_cast<const char*>(txtRecord), txtLen)))), shared_from_this()); -			return; -		} -	} -	assert(false); -} - -void AppleDNSSDService::handleHostnameResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context) { -	static_cast<AppleDNSSDService*>(context)->handleHostnameResolved(sdRef, flags, interfaceIndex, errorCode, hostname, address, ttl); -}  - -void AppleDNSSDService::handleHostnameResolved(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *rawAddress, uint32_t) { -	if (errorCode) { -		std::cerr << "Error resolving hostname" << std::endl; -		MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, boost::optional<HostAddress>()), shared_from_this()); -	} -	else { -		assert(rawAddress->sa_family == AF_INET); -		const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(rawAddress); -		uint32_t address = ntohl(sa->sin_addr.s_addr); -		MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), String(hostname), HostAddress(reinterpret_cast<unsigned char*>(&address), 4)), shared_from_this()); -	} -} - -} diff --git a/Swiften/LinkLocal/AppleDNSSDService.h b/Swiften/LinkLocal/AppleDNSSDService.h deleted file mode 100644 index fe4a648..0000000 --- a/Swiften/LinkLocal/AppleDNSSDService.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include <boost/enable_shared_from_this.hpp> -#include <boost/thread.hpp> -#include <boost/thread/mutex.hpp> -#include <dns_sd.h> - -#include "Swiften/LinkLocal/DNSSDService.h" -#include "Swiften/EventLoop/EventOwner.h" - -namespace Swift { -	class AppleDNSSDService : public DNSSDService, public EventOwner, public boost::enable_shared_from_this<AppleDNSSDService> { -		public: -			AppleDNSSDService(); -			~AppleDNSSDService(); - -			virtual void start(); -			virtual void stop(); - -			virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&); -			virtual void updateService(const LinkLocalServiceInfo&); -			virtual void unregisterService(); - -			virtual void startResolvingService(const Service&); -			virtual void stopResolvingService(const Service&); - -			virtual void resolveHostname(const String& hostname, int interfaceIndex = 0); - -		private: -			void doStart(); -			void interruptSelect(); - -			static void handleServiceDiscoveredGlobal(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, const char *, void*); -			void handleServiceDiscovered(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, const char *); -			static void handleServiceRegisteredGlobal(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType, const char *, const char *, const char *, void *); -			void handleServiceRegistered(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType, const char *, const char *, const char *); -			static void handleServiceResolvedGlobal(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, uint16_t, uint16_t, const unsigned char *, void *); -			void handleServiceResolved(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType, const char *, const char *, uint16_t, uint16_t, const unsigned char *); -			static void handleHostnameResolvedGlobal(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl, void *context); -			void handleHostnameResolved(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *hostname, const struct sockaddr *address, uint32_t ttl); - -		private: -			boost::thread* thread; -			bool stopRequested; -			bool haveError; -			int interruptSelectReadSocket; -			int interruptSelectWriteSocket; -			boost::mutex sdRefsMutex; -			DNSServiceRef browseSDRef; -			DNSServiceRef registerSDRef; -			typedef std::map<Service, DNSServiceRef> ServiceSDRefMap; -			ServiceSDRefMap resolveSDRefs; -			typedef std::vector<DNSServiceRef> HostnameSDRefs; -			HostnameSDRefs hostnameResolveSDRefs; -	}; -} diff --git a/Swiften/LinkLocal/AvahiDNSSDService.cpp b/Swiften/LinkLocal/AvahiDNSSDService.cpp deleted file mode 100644 index 1dd5c28..0000000 --- a/Swiften/LinkLocal/AvahiDNSSDService.cpp +++ /dev/null @@ -1,157 +0,0 @@ -#include "Swiften/LinkLocal/AvahiDNSSDService.h" - -#include <boost/bind.hpp> - -#include "Swiften/EventLoop/MainEventLoop.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" -#include "Swiften/Network/HostAddress.h" - -namespace Swift { - -AvahiDNSSDService::AvahiDNSSDService() : client(NULL), threadedPoll(0), serviceBrowser(0) { -} - -AvahiDNSSDService::~AvahiDNSSDService() { -} - -void AvahiDNSSDService::start() { -	threadedPoll = avahi_threaded_poll_new(); - -	int error; -	client = avahi_client_new( -			avahi_threaded_poll_get(threadedPoll),  -			static_cast<AvahiClientFlags>(0), NULL, this, &error); // TODO -	if (!client) { -		// TODO -		std::cerr << "Avahi Error: " << avahi_strerror(error) << std::endl; -		return; -	} - -	serviceBrowser = avahi_service_browser_new( -			client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,  -			"_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0),  -			handleServiceDiscoveredGlobal, this); -	if (!serviceBrowser) { -		// TODO -		std::cerr << "Avahi Error: " << avahi_strerror(error) << std::endl; -		return; -	} - -	avahi_threaded_poll_start(threadedPoll); -} - -void AvahiDNSSDService::stop() { -	avahi_threaded_poll_stop(threadedPoll); -	avahi_service_browser_free(serviceBrowser); -	avahi_client_free(client); -	avahi_threaded_poll_free(threadedPoll); -} - -void AvahiDNSSDService::registerService(const String& name, int port, const LinkLocalServiceInfo& info) { -	avahi_threaded_poll_lock(threadedPoll); -	avahi_threaded_poll_unlock(threadedPoll); -} - -void AvahiDNSSDService::updateService(const LinkLocalServiceInfo& info) { -	avahi_threaded_poll_lock(threadedPoll); -	avahi_threaded_poll_unlock(threadedPoll); -} - -void AvahiDNSSDService::unregisterService() { -	avahi_threaded_poll_lock(threadedPoll); -	avahi_threaded_poll_unlock(threadedPoll); -} - -void AvahiDNSSDService::startResolvingService(const Service& service) { -	avahi_threaded_poll_lock(threadedPoll); - -	AvahiServiceResolver* resolver = avahi_service_resolver_new( -			client,  -			service.networkInterface,  -			AVAHI_PROTO_INET, -			service.name.getUTF8Data(),  -			service.type.getUTF8Data(),  -			service.domain.getUTF8Data(),  -			AVAHI_PROTO_UNSPEC,  -			static_cast<AvahiLookupFlags>(0),  -			&AvahiDNSSDService::handleServiceResolvedGlobal,  -			this); -	assert(serviceResolvers.find(service) == serviceResolvers.end()); -	serviceResolvers[service] = resolver; - -	avahi_threaded_poll_unlock(threadedPoll); -} - -void AvahiDNSSDService::stopResolvingService(const Service& service) { -	avahi_threaded_poll_lock(threadedPoll); - -	ServiceResolverMap::iterator i = serviceResolvers.find(service); -	assert(i != serviceResolvers.end()); -	avahi_service_resolver_free(i->second); -	serviceResolvers.erase(i); - -	avahi_threaded_poll_unlock(threadedPoll); -} - -// TODO: Take interfaceIndex into account -void AvahiDNSSDService::resolveHostname(const String& hostname, int) { -	HostnameAddressMap::const_iterator i = hostnameAddresses.find(hostname); -	if (i == hostnameAddresses.end()) { -		MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, boost::optional<HostAddress>()), shared_from_this()); -	} -	else { -		MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), hostname, boost::optional<HostAddress>(i->second)), shared_from_this()); -	} -} - -void AvahiDNSSDService::handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) { -	switch(event) { -		case AVAHI_BROWSER_FAILURE: -			std::cerr << "Browse error" << std::endl; -			// TODO	 -			return; -		case AVAHI_BROWSER_NEW: { -				std::cerr << "Service added: " << name << " " << type << " " << domain << std::endl; -				Service service(name, type, domain, interfaceIndex); -				MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); -			} -			break; -		case AVAHI_BROWSER_REMOVE: { -				std::cerr << "Service removed: " << name << " " << type << " " << domain << std::endl; -				Service service(name, type, domain, interfaceIndex); -				MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); -			} -			break; -		case AVAHI_BROWSER_ALL_FOR_NOW: -		case AVAHI_BROWSER_CACHE_EXHAUSTED: -			break; -	} -} - -void AvahiDNSSDService::handleServiceResolved(AvahiServiceResolver *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) { -	switch(event) { -		case AVAHI_RESOLVER_FAILURE: -			//TODO -			std::cerr << "Resolve error" << std::endl; -			break; -		case AVAHI_RESOLVER_FOUND: -			ByteArray data; -			for(AvahiStringList* i = txt; i; i = avahi_string_list_get_next(i)) { -				char size = i->size; -				data += ByteArray(&size, 1); -				data += ByteArray(reinterpret_cast<char*>(avahi_string_list_get_text(i)), avahi_string_list_get_size(i)); -			} -			 -			assert(address->proto == AVAHI_PROTO_INET); -			HostAddress hostAddress(reinterpret_cast<const unsigned char*>(&address->data.ipv4.address), 4); -			hostnameAddresses[String(hostname)] = hostAddress; -			MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved),  -					Service(name, type, domain, interfaceIndex),  -					ResolveResult(hostname, port,  -						LinkLocalServiceInfo::createFromTXTRecord(data))), -					shared_from_this()); -			break; -	} -} - -} diff --git a/Swiften/LinkLocal/AvahiDNSSDService.h b/Swiften/LinkLocal/AvahiDNSSDService.h deleted file mode 100644 index 8d31e41..0000000 --- a/Swiften/LinkLocal/AvahiDNSSDService.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include <map> -#include <boost/enable_shared_from_this.hpp> -#include <avahi-client/client.h> -#include <avahi-client/lookup.h> -#include <avahi-common/thread-watch.h> -#include <avahi-common/watch.h> -#include <avahi-common/malloc.h> -#include <avahi-common/error.h> - - -#include "Swiften/EventLoop/EventOwner.h" -#include "Swiften/LinkLocal/DNSSDService.h" - -namespace Swift { -	class AvahiDNSSDService : public DNSSDService, public EventOwner, public boost::enable_shared_from_this<AvahiDNSSDService> { -		public: -			AvahiDNSSDService(); -			~AvahiDNSSDService(); - -			virtual void start(); -			virtual void stop(); - -			virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&); -			virtual void updateService(const LinkLocalServiceInfo&); -			virtual void unregisterService(); - -			virtual void startResolvingService(const Service&); -			virtual void stopResolvingService(const Service&); - -			virtual void resolveHostname(const String& hostname, int interfaceIndex = 0); -		 -		private: -			static void handleServiceDiscoveredGlobal(AvahiServiceBrowser *b, AvahiIfIndex networkInterface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* userdata) { -				static_cast<AvahiDNSSDService*>(userdata)->handleServiceDiscovered(b, networkInterface, protocol, event, name, type, domain, flags); -			} -			void handleServiceDiscovered(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags); - -			static void handleServiceResolvedGlobal(AvahiServiceResolver *r, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* userdata) { -				static_cast<AvahiDNSSDService*>(userdata)->handleServiceResolved(r, interfaceIndex, protocol, event, name, type, domain, hostname, address, port, txt, flags); -			} -			void handleServiceResolved(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostname, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags); - - -		private: -			AvahiClient* client; -			AvahiThreadedPoll* threadedPoll; -			AvahiServiceBrowser* serviceBrowser; -			typedef std::map<Service, AvahiServiceResolver*> ServiceResolverMap; -			ServiceResolverMap serviceResolvers; -			typedef std::map<String, HostAddress> HostnameAddressMap; -			HostnameAddressMap hostnameAddresses; -	}; -} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp new file mode 100644 index 0000000..55ccede --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp @@ -0,0 +1,59 @@ +#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h" + +#include <iostream> + +//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h" +//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h" +//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h" +//#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h" +//#include "Swiften/Base/foreach.h" + +namespace Swift { + +AvahiQuerier::AvahiQuerier() : client(NULL), threadedPoll(NULL) { +} + +AvahiQuerier::~AvahiQuerier() { +} + +boost::shared_ptr<DNSSDBrowseQuery> AvahiQuerier::createBrowseQuery() { +	//return boost::shared_ptr<DNSSDBrowseQuery>(new AvahiBrowseQuery(shared_from_this())); +} + +boost::shared_ptr<DNSSDRegisterQuery> AvahiQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) { +	//return boost::shared_ptr<DNSSDRegisterQuery>(new AvahiRegisterQuery(name, port, info, shared_from_this())); +} + +boost::shared_ptr<DNSSDResolveServiceQuery> AvahiQuerier::createResolveServiceQuery(const DNSSDServiceID& service) { +	//return boost::shared_ptr<DNSSDResolveServiceQuery>(new AvahiResolveServiceQuery(service, shared_from_this())); +} + +boost::shared_ptr<DNSSDResolveHostnameQuery> AvahiQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) { +	//return boost::shared_ptr<DNSSDResolveHostnameQuery>(new AvahiResolveHostnameQuery(hostname, interfaceIndex, shared_from_this())); +} + +void AvahiQuerier::start() { +	assert(!threadedPoll); +	threadedPoll = avahi_threaded_poll_new(); +	int error; +	assert(!client); +	client = avahi_client_new( +			avahi_threaded_poll_get(threadedPoll),  +			static_cast<AvahiClientFlags>(0), NULL, this, &error); // TODO +	if (!client) { +		// TODO +		std::cerr << "Avahi Error: " << avahi_strerror(error) << std::endl; +		return; +	} +	avahi_threaded_poll_start(threadedPoll); +} + +void AvahiQuerier::stop() { +	assert(threadedPoll); +	avahi_threaded_poll_stop(threadedPoll); +	assert(client); +	avahi_client_free(client); +	avahi_threaded_poll_free(threadedPoll); +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h new file mode 100644 index 0000000..ca45384 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h @@ -0,0 +1,39 @@ +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <avahi-client/client.h> +#include <avahi-client/lookup.h> +#include <avahi-common/thread-watch.h> +#include <avahi-common/watch.h> +#include <avahi-common/malloc.h> +#include <avahi-common/error.h> + +#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" + +namespace Swift { +	class ByteArray; + +	class AvahiQuerier :  +			public DNSSDQuerier,  +			public boost::enable_shared_from_this<AvahiQuerier> { +		public: +			AvahiQuerier(); +			~AvahiQuerier(); + +			boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); +			boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( +					const String& name, int port, const ByteArray& info); +			boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( +					const DNSSDServiceID&); +			boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( +					const String& hostname, int interfaceIndex); + +			void start(); +			void stop(); + +		private: +			AvahiClient* client; +			AvahiThreadedPoll* threadedPoll; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc b/Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc new file mode 100644 index 0000000..6150dc1 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc @@ -0,0 +1,2 @@ +SWIFTEN_SOURCES += \ +	Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h new file mode 100644 index 0000000..c605175 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { +	class BonjourQuerier; + +	class BonjourBrowseQuery : public DNSSDBrowseQuery, public BonjourQuery { +		public:	 +			BonjourBrowseQuery(boost::shared_ptr<BonjourQuerier> q) : BonjourQuery(q) { +				DNSServiceErrorType result = DNSServiceBrowse( +						&sdRef, 0, 0, "_presence._tcp", 0,  +						&BonjourBrowseQuery::handleServiceDiscoveredStatic, this); +				if (result != kDNSServiceErr_NoError) { +					sdRef = NULL; +				} +			} + +			void startBrowsing() { +				if (!sdRef) { +					MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this()); +				} +				else { +					run(); +				} +			} + +			void stopBrowsing() { +				finish(); +			} + +		private: +			static void handleServiceDiscoveredStatic(DNSServiceRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *name, const char *type, const char *domain, void *context) { +				static_cast<BonjourBrowseQuery*>(context)->handleServiceDiscovered(flags, interfaceIndex, errorCode, name, type, domain); +			} + +			void handleServiceDiscovered(DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *name, const char *type, const char *domain) { +				if (errorCode != kDNSServiceErr_NoError) { +					MainEventLoop::postEvent(boost::bind(boost::ref(onError)), shared_from_this()); +				} +				else { +					std::cout << "Discovered service: name:" << name << " domain:" << domain << " type: " << type << std::endl; +					DNSSDServiceID service(name, domain, type, interfaceIndex); +					if (flags & kDNSServiceFlagsAdd) { +						MainEventLoop::postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); +					} +					else { +						MainEventLoop::postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); +					} +				} +			} +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp new file mode 100644 index 0000000..9c9e64e --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp @@ -0,0 +1,129 @@ +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h" + +#include <unistd.h> +#include <sys/socket.h> +#include <fcntl.h> + +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h" +#include "Swiften/Base/foreach.h" + +namespace Swift { + +BonjourQuerier::BonjourQuerier() : stopRequested(false), thread(0) { +	int fds[2]; +	int result = pipe(fds); +	assert(result == 0); +	interruptSelectReadSocket = fds[0]; +	fcntl(interruptSelectReadSocket, F_SETFL, fcntl(interruptSelectReadSocket, F_GETFL)|O_NONBLOCK); +	interruptSelectWriteSocket = fds[1]; +} + +BonjourQuerier::~BonjourQuerier() { +	assert(!thread); +} + +boost::shared_ptr<DNSSDBrowseQuery> BonjourQuerier::createBrowseQuery() { +	return boost::shared_ptr<DNSSDBrowseQuery>(new BonjourBrowseQuery(shared_from_this())); +} + +boost::shared_ptr<DNSSDRegisterQuery> BonjourQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) { +	return boost::shared_ptr<DNSSDRegisterQuery>(new BonjourRegisterQuery(name, port, info, shared_from_this())); +} + +boost::shared_ptr<DNSSDResolveServiceQuery> BonjourQuerier::createResolveServiceQuery(const DNSSDServiceID& service) { +	return boost::shared_ptr<DNSSDResolveServiceQuery>(new BonjourResolveServiceQuery(service, shared_from_this())); +} + +boost::shared_ptr<DNSSDResolveHostnameQuery> BonjourQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) { +	return boost::shared_ptr<DNSSDResolveHostnameQuery>(new BonjourResolveHostnameQuery(hostname, interfaceIndex, shared_from_this())); +} + +void BonjourQuerier::addRunningQuery(boost::shared_ptr<BonjourQuery> query) { +	{ +		boost::lock_guard<boost::mutex> lock(runningQueriesMutex); +		runningQueries.push_back(query); +	} +	runningQueriesAvailableEvent.notify_one(); +	interruptSelect(); +} + +void BonjourQuerier::removeRunningQuery(boost::shared_ptr<BonjourQuery> query) { +	{ +		boost::lock_guard<boost::mutex> lock(runningQueriesMutex); +		runningQueries.erase(std::remove( +			runningQueries.begin(), runningQueries.end(), query), runningQueries.end()); +	} +} + +void BonjourQuerier::interruptSelect() { +	char c = 0; +	write(interruptSelectWriteSocket, &c, 1); +} + +void BonjourQuerier::start() { +	assert(!thread); +	thread = new boost::thread(boost::bind(&BonjourQuerier::run, shared_from_this())); +} + +void BonjourQuerier::stop() { +	if (thread) { +		stopRequested = true; +		assert(runningQueries.empty()); +		runningQueriesAvailableEvent.notify_one(); +		interruptSelect(); +		thread->join(); +		delete thread; +		thread = NULL; +		stopRequested = false; +	} +} + +void BonjourQuerier::run() { +	while (!stopRequested) { +		fd_set fdSet; +		int maxSocket; +		{ +			boost::unique_lock<boost::mutex> lock(runningQueriesMutex); +			if (runningQueries.empty()) { +				runningQueriesAvailableEvent.wait(lock); +				if (runningQueries.empty()) { +					continue; +				} +			} + +			// Run all running queries +			FD_ZERO(&fdSet); +			maxSocket = interruptSelectReadSocket; +			FD_SET(interruptSelectReadSocket, &fdSet); + +			foreach(const boost::shared_ptr<BonjourQuery>& query, runningQueries) { +				int socketID = query->getSocketID(); +				maxSocket = std::max(maxSocket, socketID); +				FD_SET(socketID, &fdSet); +			} +		} + +		if (select(maxSocket+1, &fdSet, NULL, NULL, 0) <= 0) { +			continue; +		} + +		if (FD_ISSET(interruptSelectReadSocket, &fdSet)) { +			char dummy; +			while (read(interruptSelectReadSocket, &dummy, 1) > 0) {} +		} + +		{ +			boost::lock_guard<boost::mutex> lock(runningQueriesMutex); +			foreach(boost::shared_ptr<BonjourQuery> query, runningQueries) { +				if (FD_ISSET(query->getSocketID(), &fdSet)) { +					query->processResult(); +				} +			} +		} +	} +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h new file mode 100644 index 0000000..d12f94f --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h @@ -0,0 +1,50 @@ +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <list> +#include <boost/thread.hpp> +#include <boost/thread/mutex.hpp> + +#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" + +namespace Swift { +	class ByteArray; + +	class BonjourQuerier :  +			public DNSSDQuerier,  +			public boost::enable_shared_from_this<BonjourQuerier> { +		public: +			BonjourQuerier(); +			~BonjourQuerier(); + +			boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); +			boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( +					const String& name, int port, const ByteArray& info); +			boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( +					const DNSSDServiceID&); +			boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( +					const String& hostname, int interfaceIndex); + +			void start(); +			void stop(); + +		private: +			friend class BonjourQuery; + +			void addRunningQuery(boost::shared_ptr<BonjourQuery>); +			void removeRunningQuery(boost::shared_ptr<BonjourQuery>); +			void interruptSelect(); +			void run(); + +		private: +			bool stopRequested; +			boost::thread* thread; +			boost::mutex runningQueriesMutex; +			std::list< boost::shared_ptr<BonjourQuery> > runningQueries; +			int interruptSelectReadSocket; +			int interruptSelectWriteSocket; +			boost::condition_variable runningQueriesAvailableEvent; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp new file mode 100644 index 0000000..c1c481b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp @@ -0,0 +1,31 @@ +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h" + +namespace Swift { + +BonjourQuery::BonjourQuery(boost::shared_ptr<BonjourQuerier> q) : querier(q), sdRef(0) { +} + +BonjourQuery::~BonjourQuery() { +	DNSServiceRefDeallocate(sdRef); +} + +void BonjourQuery::processResult() { +	boost::lock_guard<boost::mutex> lock(sdRefMutex); +	DNSServiceProcessResult(sdRef); +} + +int BonjourQuery::getSocketID() const { +	boost::lock_guard<boost::mutex> lock(sdRefMutex); +	return DNSServiceRefSockFD(sdRef); +} + +void BonjourQuery::run() { +	querier->addRunningQuery(shared_from_this()); +} + +void BonjourQuery::finish() { +	querier->removeRunningQuery(shared_from_this()); +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h new file mode 100644 index 0000000..bdb91a4 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h @@ -0,0 +1,32 @@ +#pragma once + +#include <dns_sd.h> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/thread/mutex.hpp> + +#include "Swiften/EventLoop/EventOwner.h" + +namespace Swift { +	class BonjourQuerier; + +	class BonjourQuery :  +			public EventOwner, +			public boost::enable_shared_from_this<BonjourQuery> { +		public: +			BonjourQuery(boost::shared_ptr<BonjourQuerier>); +			virtual ~BonjourQuery(); +			 +			void processResult(); +			int getSocketID() const; + +		protected: +			void run(); +			void finish(); +		 +		protected: +			boost::shared_ptr<BonjourQuerier> querier; +			mutable boost::mutex sdRefMutex; +			DNSServiceRef sdRef; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h new file mode 100644 index 0000000..ddc2788 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { +	class BonjourQuerier; + +	class BonjourRegisterQuery : public DNSSDRegisterQuery, public BonjourQuery { +		public:	 +			BonjourRegisterQuery(const String& name, int port, const ByteArray& txtRecord, boost::shared_ptr<BonjourQuerier> querier) : BonjourQuery(querier) { +				DNSServiceErrorType result = DNSServiceRegister( +						&sdRef, 0, 0, name.getUTF8Data(), "_presence._tcp", NULL, NULL, port,  +						txtRecord.getSize(), txtRecord.getData(),  +						&BonjourRegisterQuery::handleServiceRegisteredStatic, this); +				if (result != kDNSServiceErr_NoError) { +					sdRef = NULL; +				} +			} + +			void registerService() { +				if (sdRef) { +					run(); +				} +				else { +					MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); +				} +			} + +			void unregisterService() { +				finish(); +			} + +			void updateServiceInfo(const ByteArray& txtRecord) { +				boost::lock_guard<boost::mutex> lock(sdRefMutex); +				DNSServiceUpdateRecord(sdRef, NULL, NULL, txtRecord.getSize(), txtRecord.getData(), 0); +			} + +		private: +			static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { +				static_cast<BonjourRegisterQuery*>(context)->handleServiceRegistered(errorCode, name, regtype, domain); +			} + +			void handleServiceRegistered(DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain) { +				if (errorCode != kDNSServiceErr_NoError) { +					MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); +				} +				else { +					MainEventLoop::postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, domain, regtype, 0))), shared_from_this()); +				} +			} +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h new file mode 100644 index 0000000..7b5f19a --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h @@ -0,0 +1,63 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" +#include "Swiften/EventLoop/MainEventLoop.h" +#include "Swiften/Network/HostAddress.h" + +#include <netinet/in.h> + +namespace Swift { +	class BonjourQuerier; + +	class BonjourResolveHostnameQuery : public DNSSDResolveHostnameQuery, public BonjourQuery { +		public:  +			BonjourResolveHostnameQuery(const String& hostname, int interfaceIndex, boost::shared_ptr<BonjourQuerier> querier) : BonjourQuery(querier) { +				DNSServiceErrorType result = DNSServiceGetAddrInfo( +						&sdRef, 0, interfaceIndex, kDNSServiceProtocol_IPv4,  +						hostname.getUTF8Data(),  +						&BonjourResolveHostnameQuery::handleHostnameResolvedStatic, this); +				if (result != kDNSServiceErr_NoError) { +					sdRef = NULL; +				} +			} + +			//void DNSSDResolveHostnameQuery::run() { +			void run() { +				if (sdRef) { +					BonjourQuery::run(); +				} +				else { +					MainEventLoop::postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>()), shared_from_this()); +				} +			} + +			void finish() { +				BonjourQuery::finish(); +			} + +		private: +			static void handleHostnameResolvedStatic(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char*, const struct sockaddr *address, uint32_t, void *context) { +				static_cast<BonjourResolveHostnameQuery*>(context)->handleHostnameResolved(errorCode, address); +			}  + +			void handleHostnameResolved(DNSServiceErrorType errorCode, const struct sockaddr *rawAddress) { +				if (errorCode) { +					MainEventLoop::postEvent( +								boost::bind(boost::ref(onHostnameResolved),  +								boost::optional<HostAddress>()),  +							shared_from_this()); +				} +				else { +					assert(rawAddress->sa_family == AF_INET); +					const sockaddr_in* sa = reinterpret_cast<const sockaddr_in*>(rawAddress); +					uint32_t address = ntohl(sa->sin_addr.s_addr); +					MainEventLoop::postEvent(boost::bind( +								boost::ref(onHostnameResolved),  +								HostAddress(reinterpret_cast<unsigned char*>(&address), 4)),  +							shared_from_this()); +				} +			} +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h new file mode 100644 index 0000000..886b87b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h @@ -0,0 +1,58 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { +	class BonjourQuerier; + +	class BonjourResolveServiceQuery : public DNSSDResolveServiceQuery, public BonjourQuery { +		public:	 +			BonjourResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<BonjourQuerier> querier) : BonjourQuery(querier) { +				DNSServiceErrorType result = DNSServiceResolve( +						&sdRef, 0, service.getNetworkInterfaceID(),  +						service.getName().getUTF8Data(), service.getType().getUTF8Data(),  +						service.getDomain().getUTF8Data(),  +						&BonjourResolveServiceQuery::handleServiceResolvedStatic, this); +				if (result != kDNSServiceErr_NoError) { +					sdRef = NULL; +				} +			} + +			void start() { +				if (sdRef) { +					run(); +				} +				else { +					MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); +				} +			} + +			void stop() { +				finish(); +			} + +		private: +			static void handleServiceResolvedStatic(DNSServiceRef, DNSServiceFlags, uint32_t, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) { +				static_cast<BonjourResolveServiceQuery*>(context)->handleServiceResolved(errorCode, fullname, hosttarget, port, txtLen, txtRecord); +			} + +			void handleServiceResolved(DNSServiceErrorType errorCode, const char* fullName, const char* host, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord) { +				if (errorCode != kDNSServiceErr_NoError) { +					MainEventLoop::postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); +				} +				else { +					std::cout << "Service resolved: name:" << fullName << " host:" << host << " port:" << port << std::endl; +					MainEventLoop::postEvent( +							boost::bind( +								boost::ref(onServiceResolved),  +								Result(String(fullName), String(host), port,  +									ByteArray(reinterpret_cast<const char*>(txtRecord), txtLen))),  +							shared_from_this()); +				} +			} +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc b/Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc new file mode 100644 index 0000000..efa329d --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc @@ -0,0 +1,3 @@ +SWIFTEN_SOURCES += \ +	Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp \ +	Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp new file mode 100644 index 0000000..1dbff2c --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp @@ -0,0 +1,8 @@ +#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" + +namespace Swift { + +DNSSDBrowseQuery::~DNSSDBrowseQuery() { +} + +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h new file mode 100644 index 0000000..9b30858 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h @@ -0,0 +1,19 @@ +#pragma once + +#include <boost/signal.hpp> + +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" + +namespace Swift { +	class DNSSDBrowseQuery { +		public: +			virtual ~DNSSDBrowseQuery(); + +			virtual void startBrowsing() = 0; +			virtual void stopBrowsing() = 0; + +			boost::signal<void (const DNSSDServiceID&)> onServiceAdded; +			boost::signal<void (const DNSSDServiceID&)> onServiceRemoved; +			boost::signal<void ()> onError; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp new file mode 100644 index 0000000..cc8d6ef --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp @@ -0,0 +1,8 @@ +#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" + +namespace Swift { + +DNSSDQuerier::~DNSSDQuerier() { +} + +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h new file mode 100644 index 0000000..799bc0c --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h @@ -0,0 +1,26 @@ +#pragma once + +#include <boost/shared_ptr.hpp> + +namespace Swift { +	class String; +	class ByteArray; +	class DNSSDServiceID; +	class DNSSDBrowseQuery; +	class DNSSDRegisterQuery; +	class DNSSDResolveServiceQuery; +	class DNSSDResolveHostnameQuery; + +	class DNSSDQuerier { +		public: +			virtual ~DNSSDQuerier(); + +			virtual boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery() = 0; +			virtual boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( +					const String& name, int port, const ByteArray& info) = 0; +			virtual boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( +					const DNSSDServiceID&) = 0; +			virtual boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( +					const String& hostname, int interfaceIndex) = 0; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp new file mode 100644 index 0000000..bbb8692 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp @@ -0,0 +1,8 @@ +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" + +namespace Swift { + +DNSSDRegisterQuery::~DNSSDRegisterQuery() { +} + +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h new file mode 100644 index 0000000..4a04fa9 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h @@ -0,0 +1,21 @@ +#pragma once + +#include <boost/signal.hpp> +#include <boost/optional.hpp> + +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" + +namespace Swift { +	class ByteArray; + +	class DNSSDRegisterQuery { +		public: +			virtual ~DNSSDRegisterQuery(); + +			virtual void registerService() = 0; +			virtual void unregisterService() = 0; +			virtual void updateServiceInfo(const ByteArray& info) = 0; + +			boost::signal<void (boost::optional<DNSSDServiceID>)> onRegisterFinished; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp new file mode 100644 index 0000000..e247e39 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp @@ -0,0 +1,8 @@ +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" + +namespace Swift { + +DNSSDResolveHostnameQuery::~DNSSDResolveHostnameQuery() { +} + +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h new file mode 100644 index 0000000..1b9f291 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h @@ -0,0 +1,18 @@ +#pragma once + +#include <boost/signal.hpp> +#include <boost/optional.hpp> + +#include "Swiften/Network/HostAddress.h" + +namespace Swift { +	class DNSSDResolveHostnameQuery { +		public: +			virtual ~DNSSDResolveHostnameQuery(); + +			virtual void run() = 0; +			virtual void finish() = 0; + +			boost::signal<void (const boost::optional<HostAddress>&)> onHostnameResolved; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp new file mode 100644 index 0000000..67a5d66 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp @@ -0,0 +1,8 @@ +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" + +namespace Swift { + +DNSSDResolveServiceQuery::~DNSSDResolveServiceQuery() { +} + +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h new file mode 100644 index 0000000..217e396 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h @@ -0,0 +1,28 @@ +#pragma once + +#include <boost/signal.hpp> +#include <boost/optional.hpp> + +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { +	class DNSSDResolveServiceQuery { +		public: +			struct Result { +				Result(const String& fullName, const String& host, int port, const ByteArray& info) :  +							fullName(fullName), host(host), port(port), info(info) {} +				String fullName; +				String host; +				int port; +				ByteArray info; +			}; + +			virtual ~DNSSDResolveServiceQuery(); + +			virtual void start() = 0; +			virtual void stop() = 0; + +			boost::signal<void (const boost::optional<Result>&)> onServiceResolved; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp new file mode 100644 index 0000000..b360ee5 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp @@ -0,0 +1,7 @@ +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" + +namespace Swift { + +const char* DNSSDServiceID::PresenceServiceType = "_presence._tcp"; + +} diff --git a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h new file mode 100644 index 0000000..ba7828b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Swiften/Base/String.h" + +namespace Swift { +	class DNSSDServiceID { +		public: +			static const char* PresenceServiceType; + +			DNSSDServiceID( +				const String& name,  +				const String& domain,  +				const String& type = PresenceServiceType,  +				int networkInterface = 0) :  +					name(name),  +					domain(domain),  +					type(type),  +					networkInterface(networkInterface) { +			} + +			bool operator==(const DNSSDServiceID& o) const { +				return name == o.name && domain == o.domain && type == o.type && (networkInterface != 0 && o.networkInterface != 0 ? networkInterface == o.networkInterface : true); +			} + +			bool operator<(const DNSSDServiceID& o) const { +				if (o.name == name) { +					if (o.domain == domain) { +						if (o.type == type) { +							return networkInterface < o.networkInterface; +						} +						else { +							return type < o.type; +						} +					} +					else { +						return domain < o.domain; +					} +				} +				else { +					return o.name < name; +				} +			} + +			const String& getName() const { +				return name; +			} + +			const String& getDomain() const { +				return domain; +			} + +			const String& getType() const { +				return type; +			} + +			int getNetworkInterfaceID() const { +				return networkInterface; +			} + +		private: +			String name; +			String domain; +			String type; +			int networkInterface; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h new file mode 100644 index 0000000..5a0b93b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h @@ -0,0 +1,22 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" + +namespace Swift { +	class FakeDNSSDQuerier; + +	class FakeDNSSDBrowseQuery : public DNSSDBrowseQuery, public FakeDNSSDQuery { +		public:	 +			FakeDNSSDBrowseQuery(boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier) { +			} + +			void startBrowsing() { +				run(); +			} + +			void stopBrowsing() { +				finish(); +			} +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp new file mode 100644 index 0000000..5079192 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp @@ -0,0 +1,105 @@ +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" + +#include <boost/bind.hpp> + +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h" +#include "Swiften/EventLoop/MainEventLoop.h" + +namespace Swift { + +FakeDNSSDQuerier::FakeDNSSDQuerier(const String& domain) : domain(domain) { +} + +boost::shared_ptr<DNSSDBrowseQuery> FakeDNSSDQuerier::createBrowseQuery() { +	return boost::shared_ptr<DNSSDBrowseQuery>(new FakeDNSSDBrowseQuery(shared_from_this())); +} + +boost::shared_ptr<DNSSDRegisterQuery> FakeDNSSDQuerier::createRegisterQuery(const String& name, int port, const ByteArray& info) { +	return boost::shared_ptr<DNSSDRegisterQuery>(new FakeDNSSDRegisterQuery(name, port, info, shared_from_this())); +} + +boost::shared_ptr<DNSSDResolveServiceQuery> FakeDNSSDQuerier::createResolveServiceQuery(const DNSSDServiceID& service) { +	return boost::shared_ptr<DNSSDResolveServiceQuery>(new FakeDNSSDResolveServiceQuery(service, shared_from_this())); +} + +boost::shared_ptr<DNSSDResolveHostnameQuery> FakeDNSSDQuerier::createResolveHostnameQuery(const String& hostname, int interfaceIndex) { +	return boost::shared_ptr<DNSSDResolveHostnameQuery>(new FakeDNSSDResolveHostnameQuery(hostname, interfaceIndex, shared_from_this())); +} + +void FakeDNSSDQuerier::addRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) { +	runningQueries.push_back(query); +	if (boost::shared_ptr<FakeDNSSDBrowseQuery> browseQuery = boost::dynamic_pointer_cast<FakeDNSSDBrowseQuery>(query)) { +		foreach(const DNSSDServiceID& service, services) { +			MainEventLoop::postEvent(boost::bind(boost::ref(browseQuery->onServiceAdded), service), shared_from_this()); +		} +	} +	else if (boost::shared_ptr<FakeDNSSDResolveServiceQuery> resolveQuery = boost::dynamic_pointer_cast<FakeDNSSDResolveServiceQuery>(query)) { +		for(ServiceInfoMap::const_iterator i = serviceInfo.begin(); i != serviceInfo.end(); ++i) { +			if (i->first == resolveQuery->service) { +				MainEventLoop::postEvent(boost::bind(boost::ref(resolveQuery->onServiceResolved), i->second), shared_from_this()); +			} +		} +	} +	else if (boost::shared_ptr<FakeDNSSDRegisterQuery> registerQuery = boost::dynamic_pointer_cast<FakeDNSSDRegisterQuery>(query)) { +		DNSSDServiceID service(registerQuery->name, domain); +		MainEventLoop::postEvent(boost::bind(boost::ref(registerQuery->onRegisterFinished), service), shared_from_this()); +	} +} + +void FakeDNSSDQuerier::removeRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) { +	runningQueries.erase(std::remove( +		runningQueries.begin(), runningQueries.end(), query), runningQueries.end()); +} + +void FakeDNSSDQuerier::addService(const DNSSDServiceID& id) { +	services.insert(id); +	foreach(const boost::shared_ptr<FakeDNSSDBrowseQuery>& query, getQueries<FakeDNSSDBrowseQuery>()) { +		MainEventLoop::postEvent(boost::bind(boost::ref(query->onServiceAdded), id), shared_from_this()); +	} +} + +void FakeDNSSDQuerier::removeService(const DNSSDServiceID& id) { +	services.erase(id); +	serviceInfo.erase(id); +	foreach(const boost::shared_ptr<FakeDNSSDBrowseQuery>& query, getQueries<FakeDNSSDBrowseQuery>()) { +		MainEventLoop::postEvent(boost::bind(boost::ref(query->onServiceRemoved), id), shared_from_this()); +	} +} + +void FakeDNSSDQuerier::setServiceInfo(const DNSSDServiceID& id, const DNSSDResolveServiceQuery::Result& info) { +	std::pair<ServiceInfoMap::iterator, bool> r = serviceInfo.insert(std::make_pair(id, info)); +	if (!r.second) { +		r.first->second = info; +	} +	foreach(const boost::shared_ptr<FakeDNSSDResolveServiceQuery>& query, getQueries<FakeDNSSDResolveServiceQuery>()) { +		if (query->service == id) { +			MainEventLoop::postEvent(boost::bind(boost::ref(query->onServiceResolved), info), shared_from_this()); +		} +	} +} + +bool FakeDNSSDQuerier::isServiceRegistered(const String& name, int port, const ByteArray& info) { +	foreach(const boost::shared_ptr<FakeDNSSDRegisterQuery>& query, getQueries<FakeDNSSDRegisterQuery>()) { +		if (query->name == name && query->port == port && query->info == info) { +			return true; +		} +	} +	return false; +} + +void FakeDNSSDQuerier::setBrowseError() { +	foreach(const boost::shared_ptr<FakeDNSSDBrowseQuery>& query, getQueries<FakeDNSSDBrowseQuery>()) { +		MainEventLoop::postEvent(boost::ref(query->onError), shared_from_this()); +	} +} + +void FakeDNSSDQuerier::setRegisterError() { +	foreach(const boost::shared_ptr<FakeDNSSDRegisterQuery>& query, getQueries<FakeDNSSDRegisterQuery>()) { +		MainEventLoop::postEvent(boost::bind(boost::ref(query->onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); +	} +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h new file mode 100644 index 0000000..f2ec17b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h @@ -0,0 +1,63 @@ +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <list> +#include <set> + +#include "Swiften/Base/foreach.h" +#include "Swiften/EventLoop/EventOwner.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" + +namespace Swift { +	class ByteArray; +	class FakeDNSSDQuery; +	class FakeDNSSDBrowseQuery; + +	class FakeDNSSDQuerier :  +			public DNSSDQuerier,  +			public EventOwner, +			public boost::enable_shared_from_this<FakeDNSSDQuerier> { +		public: +			FakeDNSSDQuerier(const String& domain); + +			boost::shared_ptr<DNSSDBrowseQuery> createBrowseQuery(); +			boost::shared_ptr<DNSSDRegisterQuery> createRegisterQuery( +					const String& name, int port, const ByteArray& info); +			boost::shared_ptr<DNSSDResolveServiceQuery> createResolveServiceQuery( +					const DNSSDServiceID&); +			boost::shared_ptr<DNSSDResolveHostnameQuery> createResolveHostnameQuery( +					const String& hostname, int interfaceIndex); + +			void addRunningQuery(boost::shared_ptr<FakeDNSSDQuery>); +			void removeRunningQuery(boost::shared_ptr<FakeDNSSDQuery>); + +			void addService(const DNSSDServiceID& id); +			void removeService(const DNSSDServiceID& id); +			void setServiceInfo(const DNSSDServiceID& id, const DNSSDResolveServiceQuery::Result& info); +			bool isServiceRegistered(const String& name, int port, const ByteArray& info); + +			void setBrowseError(); +			void setRegisterError(); + +		private: +			template<typename T> +			std::vector< boost::shared_ptr<T> > getQueries() const { +				std::vector< boost::shared_ptr<T> > result; +				foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, runningQueries) { +					if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) { +						result.push_back(resultQuery); +					} +				} +				return result; +			} + +		private: +			String domain; +			std::list< boost::shared_ptr<FakeDNSSDQuery> > runningQueries; +			std::set<DNSSDServiceID> services; +			typedef std::map<DNSSDServiceID,DNSSDResolveServiceQuery::Result> ServiceInfoMap; +			ServiceInfoMap serviceInfo; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp new file mode 100644 index 0000000..ced7850 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp @@ -0,0 +1,20 @@ +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" + +namespace Swift { + +FakeDNSSDQuery::FakeDNSSDQuery(boost::shared_ptr<FakeDNSSDQuerier> querier) : querier(querier) { +} + +FakeDNSSDQuery::~FakeDNSSDQuery() { +} + +void FakeDNSSDQuery::run() { +	querier->addRunningQuery(shared_from_this()); +} + +void FakeDNSSDQuery::finish() { +	querier->removeRunningQuery(shared_from_this()); +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h new file mode 100644 index 0000000..9fca1d4 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h @@ -0,0 +1,25 @@ +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include "Swiften/EventLoop/EventOwner.h" + +namespace Swift { +	class FakeDNSSDQuerier; + +	class FakeDNSSDQuery :  +			public EventOwner, +			public boost::enable_shared_from_this<FakeDNSSDQuery> { +		public: +			FakeDNSSDQuery(boost::shared_ptr<FakeDNSSDQuerier>); +			virtual ~FakeDNSSDQuery(); +			 +		protected: +			void run(); +			void finish(); +		 +		protected: +			boost::shared_ptr<FakeDNSSDQuerier> querier; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h new file mode 100644 index 0000000..82ec623 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/Base/String.h" + +namespace Swift { +	class FakeDNSSDQuerier; + +	class FakeDNSSDRegisterQuery : public DNSSDRegisterQuery, public FakeDNSSDQuery { +		public:	 +			FakeDNSSDRegisterQuery(const String& name, int port, const ByteArray& info, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), name(name), port(port), info(info) { +			} + +			void registerService() { +				run(); +			} + +			void updateServiceInfo(const ByteArray& i) { +				info = i; +			} + +			void unregisterService() { +				finish(); +			} + +			String name; +			int port; +			ByteArray info; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h new file mode 100644 index 0000000..1f9d7f1 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" +#include "Swiften/Network/HostAddress.h" + +#include <netinet/in.h> + +namespace Swift { +	class FakeDNSSDQuerier; + +	class FakeDNSSDResolveHostnameQuery : public DNSSDResolveHostnameQuery, public FakeDNSSDQuery { +		public:	 +			FakeDNSSDResolveHostnameQuery(const String& hostname, int interfaceIndex, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), hostname(hostname), interfaceIndex(interfaceIndex) { +			} + +			void run() { +				FakeDNSSDQuery::run(); +			} + +			void finish() { +				FakeDNSSDQuery::finish(); +			} + +			String hostname; +			int interfaceIndex; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h new file mode 100644 index 0000000..60d35e5 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" + +namespace Swift { +	class FakeDNSSDQuerier; + +	class FakeDNSSDResolveServiceQuery : public DNSSDResolveServiceQuery, public FakeDNSSDQuery { +		public:	 +			FakeDNSSDResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<FakeDNSSDQuerier> querier) : FakeDNSSDQuery(querier), service(service) { +			} + +			void start() { +				run(); +			} + +			void stop() { +				finish(); +			} + +			DNSSDServiceID service; +	}; +} diff --git a/Swiften/LinkLocal/DNSSD/Fake/Makefile.inc b/Swiften/LinkLocal/DNSSD/Fake/Makefile.inc new file mode 100644 index 0000000..316d061 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Fake/Makefile.inc @@ -0,0 +1,3 @@ +SWIFTEN_SOURCES += \ +	Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp \ +	Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp diff --git a/Swiften/LinkLocal/DNSSD/Makefile.inc b/Swiften/LinkLocal/DNSSD/Makefile.inc new file mode 100644 index 0000000..f6997ef --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Makefile.inc @@ -0,0 +1,16 @@ +SWIFTEN_SOURCES += \ +	Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp \ +	Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp \ +	Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp \ +	Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp \ +	Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp \ +	Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp + +ifeq ($(HAVE_BONJOUR),yes) +include Swiften/LinkLocal/DNSSD/Bonjour/Makefile.inc +endif +ifeq ($(HAVE_AVAHI),yes) +include Swiften/LinkLocal/DNSSD/Avahi/Makefile.inc +endif + +include Swiften/LinkLocal/DNSSD/Fake/Makefile.inc diff --git a/Swiften/LinkLocal/DNSSDService.cpp b/Swiften/LinkLocal/DNSSDService.cpp deleted file mode 100644 index 9545981..0000000 --- a/Swiften/LinkLocal/DNSSDService.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "Swiften/LinkLocal/DNSSDService.h" - -namespace Swift { - -DNSSDService::~DNSSDService() { -} - -} diff --git a/Swiften/LinkLocal/DNSSDService.h b/Swiften/LinkLocal/DNSSDService.h deleted file mode 100644 index 9689352..0000000 --- a/Swiften/LinkLocal/DNSSDService.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include <boost/signal.hpp> -#include <map> - -#include "Swiften/Base/String.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" - -namespace Swift { -	class LinkLocalServiceInfo; -	class HostAddress; - -	class DNSSDService { -		public: -			struct Service { -				Service(const String& name, const String& type, const String& domain, int networkInterface) : name(name), type(type), domain(domain), networkInterface(networkInterface) {} -				bool operator==(const Service& o) const { -					return name == o.name && type == o.type && domain == o.domain && (networkInterface != 0 && o.networkInterface != 0 ? networkInterface == o.networkInterface : true); -				} -				bool operator<(const Service& o) const { -					if (o.name == name) { -						if (o.type == type) { -							if (o.domain == domain) { -								return networkInterface < o.networkInterface; -							} -							else { -								return domain < o.domain; -							} -						} -						else { -							return type < o.type; -						} -					} -					else { -						return o.name < name; -					} -				} - -				String name; -				String type; -				String domain; -				int networkInterface; -			}; - -			struct ResolveResult { -				ResolveResult(const String& host, int port, const LinkLocalServiceInfo& info) : host(host), port(port), info(info) {} -				String host; -				int port; -				LinkLocalServiceInfo info; -			}; - -			virtual ~DNSSDService(); - -			virtual void start() = 0; -			virtual void stop() = 0; - -			virtual void registerService(const String& name, int port, const LinkLocalServiceInfo&) = 0; -			virtual void updateService(const LinkLocalServiceInfo&) = 0; -			virtual void unregisterService() = 0; - -			virtual void startResolvingService(const Service&) = 0; -			virtual void stopResolvingService(const Service&) = 0; -			 -			virtual void resolveHostname(const String& hostname, int interfaceIndex = 0) = 0; - -			boost::signal<void ()> onStarted; -			boost::signal<void (bool)> onStopped; -			boost::signal<void (const Service&)> onServiceAdded; -			boost::signal<void (const Service&)> onServiceRemoved; -			boost::signal<void (const Service&)> onServiceRegistered; -			boost::signal<void (const Service&, const ResolveResult&)> onServiceResolved; -			boost::signal<void (const String&, const boost::optional<HostAddress>&)> onHostnameResolved; -	}; -} diff --git a/Swiften/LinkLocal/LinkLocalConnector.cpp b/Swiften/LinkLocal/LinkLocalConnector.cpp index af521b0..18b5d6a 100644 --- a/Swiften/LinkLocal/LinkLocalConnector.cpp +++ b/Swiften/LinkLocal/LinkLocalConnector.cpp @@ -6,42 +6,45 @@  #include "Swiften/Network/ConnectionFactory.h"  #include "Swiften/Network/HostAddress.h"  #include "Swiften/Network/HostAddressPort.h" -#include "Swiften/LinkLocal/DNSSDService.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h"  namespace Swift {  LinkLocalConnector::LinkLocalConnector(  		const JID& remoteJID,  		const String& hostname, +		int interfaceIndex,  		int port, -		boost::shared_ptr<DNSSDService> resolver, +		boost::shared_ptr<DNSSDQuerier> querier,  		boost::shared_ptr<Connection> connection) :  -			remoteJID_(remoteJID), -			hostname_(hostname), -			port_(port), -			resolver_(resolver), -			connection_(connection), -			resolving_(false) { +			remoteJID(remoteJID), +			hostname(hostname), +			interfaceIndex(interfaceIndex), +			port(port), +			querier(querier), +			connection(connection) {  }  void LinkLocalConnector::connect() { -	resolving_ = true; -	resolver_->onHostnameResolved.connect(boost::bind(&LinkLocalConnector::handleHostnameResolved, boost::dynamic_pointer_cast<LinkLocalConnector>(shared_from_this()), _1, _2)); -	resolver_->resolveHostname(hostname_); +	resolveQuery = querier->createResolveHostnameQuery(hostname, interfaceIndex); +	resolveQuery->onHostnameResolved.connect(boost::bind( +			&LinkLocalConnector::handleHostnameResolved,  +			boost::dynamic_pointer_cast<LinkLocalConnector>(shared_from_this()),  +			_1)); +	resolveQuery->run();  } -void LinkLocalConnector::handleHostnameResolved(const String& hostname, const boost::optional<HostAddress>& address) { -	if (resolving_) { -		if (hostname == hostname_) { -			resolving_ = false; -			if (address) { -				connection_->onConnectFinished.connect(boost::bind(boost::ref(onConnectFinished), _1)); -				connection_->connect(HostAddressPort(*address, port_)); -			} -			else { -				onConnectFinished(false); -			} -		} +void LinkLocalConnector::handleHostnameResolved(const boost::optional<HostAddress>& address) { +	if (address) { +		resolveQuery->finish(); +		resolveQuery.reset(); +		connection->onConnectFinished.connect( +				boost::bind(boost::ref(onConnectFinished), _1)); +		connection->connect(HostAddressPort(*address, port)); +	} +	else { +		onConnectFinished(false);  	}  } @@ -50,7 +53,7 @@ void LinkLocalConnector::handleConnected(bool error) {  }  void LinkLocalConnector::queueElement(boost::shared_ptr<Element> element) { -	queuedElements_.push_back(element); +	queuedElements.push_back(element);  } diff --git a/Swiften/LinkLocal/LinkLocalConnector.h b/Swiften/LinkLocal/LinkLocalConnector.h index d296804..134656c 100644 --- a/Swiften/LinkLocal/LinkLocalConnector.h +++ b/Swiften/LinkLocal/LinkLocalConnector.h @@ -15,45 +15,48 @@ namespace Swift {  	class Element;  	class PayloadParserFactoryCollection;  	class PayloadSerializerCollection; -	class DNSSDService; +	class DNSSDQuerier; +	class DNSSDResolveHostnameQuery;  	class LinkLocalConnector : public boost::enable_shared_from_this<LinkLocalConnector> {  		public:  			LinkLocalConnector(  					const JID& remoteJID,  					const String& hostname, +					int interfaceIndex,  					int port, -					boost::shared_ptr<DNSSDService> resolver, +					boost::shared_ptr<DNSSDQuerier> querier,  					boost::shared_ptr<Connection> connection);  			const JID& getRemoteJID() const { -				return remoteJID_; +				return remoteJID;  			}  			void connect();  			void queueElement(boost::shared_ptr<Element> element);  			const std::vector<boost::shared_ptr<Element> >& getQueuedElements() const { -				return queuedElements_; +				return queuedElements;  			}  			boost::shared_ptr<Connection> getConnection() const { -				return connection_; +				return connection;  			}  			boost::signal<void (bool)> onConnectFinished;  		private: -			void handleHostnameResolved(const String& hostname, const boost::optional<HostAddress>& address); +			void handleHostnameResolved(const boost::optional<HostAddress>& address);  			void handleConnected(bool error);  		private: -			JID remoteJID_; -			String hostname_; -			int port_; -			boost::shared_ptr<DNSSDService> resolver_; -			boost::shared_ptr<Connection> connection_; -			bool resolving_; -			std::vector<boost::shared_ptr<Element> > queuedElements_; +			JID remoteJID; +			String hostname; +			int interfaceIndex; +			int port; +			boost::shared_ptr<DNSSDQuerier> querier; +			boost::shared_ptr<DNSSDResolveHostnameQuery> resolveQuery; +			boost::shared_ptr<Connection> connection; +			std::vector<boost::shared_ptr<Element> > queuedElements;  	};  } diff --git a/Swiften/LinkLocal/LinkLocalRoster.cpp b/Swiften/LinkLocal/LinkLocalRoster.cpp deleted file mode 100644 index 25143a6..0000000 --- a/Swiften/LinkLocal/LinkLocalRoster.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include <boost/bind.hpp> -#include <iostream> - -#include "Swiften/LinkLocal/LinkLocalRoster.h" -#include "Swiften/Network/HostAddress.h" - -namespace Swift { - -LinkLocalRoster::LinkLocalRoster(boost::shared_ptr<DNSSDService> service) : dnsSDService(service) { -	dnsSDService->onStopped.connect(boost::bind(&LinkLocalRoster::handleStopped, this, _1)); -	dnsSDService->onServiceRegistered.connect(boost::bind(&LinkLocalRoster::handleServiceRegistered, this, _1)); -	dnsSDService->onServiceAdded.connect(boost::bind(&LinkLocalRoster::handleServiceAdded, this, _1)); -	dnsSDService->onServiceRemoved.connect(boost::bind(&LinkLocalRoster::handleServiceRemoved, this, _1)); -	dnsSDService->onServiceResolved.connect(boost::bind(&LinkLocalRoster::handleServiceResolved, this, _1, _2)); -} - -boost::shared_ptr<RosterPayload> LinkLocalRoster::getRoster() const { -	boost::shared_ptr<RosterPayload> roster(new RosterPayload()); -	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) { -		roster->addItem(getRosterItem(i->first, i->second)); -	} -	return roster; -} - -std::vector<boost::shared_ptr<Presence> > LinkLocalRoster::getAllPresence() const { -	std::vector<boost::shared_ptr<Presence> > result; -	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) { -		result.push_back(getPresence(i->first, i->second)); -	} -	return result; -} - -RosterItemPayload LinkLocalRoster::getRosterItem(const DNSSDService::Service& service, const DNSSDService::ResolveResult& resolveResult) const { - return RosterItemPayload(getJIDForService(service), getRosterName(service, resolveResult), RosterItemPayload::Both); -} - -String LinkLocalRoster::getRosterName(const DNSSDService::Service& service, const DNSSDService::ResolveResult& resolveResult) const { -	if (!resolveResult.info.getNick().isEmpty()) { -		return resolveResult.info.getNick(); -	} -	else if (!resolveResult.info.getFirstName().isEmpty()) { -		String result = resolveResult.info.getFirstName(); -		if (!resolveResult.info.getLastName().isEmpty()) { -			result += " " + resolveResult.info.getLastName(); -		} -		return result; -	} -	else if (!resolveResult.info.getLastName().isEmpty()) { -		return resolveResult.info.getLastName(); -	} -	return service.name; -} - -JID LinkLocalRoster::getJIDForService(const DNSSDService::Service& service) const { -	return JID(service.name); -} - -boost::shared_ptr<Presence> LinkLocalRoster::getPresence(const DNSSDService::Service& service, const DNSSDService::ResolveResult& resolveResult) const { -	boost::shared_ptr<Presence> presence(new Presence()); -	presence->setFrom(getJIDForService(service)); -	switch (resolveResult.info.getStatus()) { -		case LinkLocalServiceInfo::Available: -			presence->setShow(StatusShow::Online); -			break; -		case LinkLocalServiceInfo::Away: -			presence->setShow(StatusShow::Away); -			break; -		case LinkLocalServiceInfo::DND: -			presence->setShow(StatusShow::DND); -			break; -	} -	presence->setStatus(resolveResult.info.getMessage()); -	return presence; -} - -void LinkLocalRoster::handleServiceAdded(const DNSSDService::Service& service) { -	if (selfService && *selfService == service) { -		return; -	} -	dnsSDService->startResolvingService(service); -} - -void LinkLocalRoster::handleServiceRemoved(const DNSSDService::Service& service) { -	if (selfService && *selfService == service) { -		return; -	} -	dnsSDService->stopResolvingService(service); -	services.erase(service); -	boost::shared_ptr<RosterPayload> roster(new RosterPayload()); -	roster->addItem(RosterItemPayload(getJIDForService(service), "", RosterItemPayload::Remove)); -	onRosterChanged(roster); -} - -void LinkLocalRoster::handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result) { -	std::pair<ServiceMap::iterator, bool> r = services.insert(std::make_pair(service, result)); -	if (r.second) { -		boost::shared_ptr<RosterPayload> roster(new RosterPayload()); -		roster->addItem(getRosterItem(service, result)); -		onRosterChanged(roster); -	} -	else { -		r.first->second = result; -	} -	onPresenceChanged(getPresence(service, result)); -} - -void LinkLocalRoster::handleServiceRegistered(const DNSSDService::Service& service) { -	selfService = service; -} - -void LinkLocalRoster::handleStopped(bool error) { -	std::cout << "DNSSDService stopped: " << error << std::endl; -} - -bool LinkLocalRoster::hasItem(const JID& j) const { -	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) { -		if (getJIDForService(i->first) == j) { -			return true; -		} -	} -	return false; -} - -String LinkLocalRoster::getHostname(const JID& j) const { -	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) { -		if (getJIDForService(i->first) == j) { -			return i->second.host; -		} -	} -	return ""; -} - -int LinkLocalRoster::getPort(const JID& j) const { -	for(ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) { -		if (getJIDForService(i->first) == j) { -			return i->second.port; -		} -	} -	return 0; -} - -} diff --git a/Swiften/LinkLocal/LinkLocalRoster.h b/Swiften/LinkLocal/LinkLocalRoster.h deleted file mode 100644 index c18d8fc..0000000 --- a/Swiften/LinkLocal/LinkLocalRoster.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> -#include <set> - -#include "Swiften/Base/String.h" -#include "Swiften/JID/JID.h" -#include "Swiften/LinkLocal/DNSSDService.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Elements/Presence.h" - -namespace Swift { -	class HostAddress; - -	class LinkLocalRoster { -		public: -			LinkLocalRoster(boost::shared_ptr<DNSSDService> service); - -			boost::shared_ptr<RosterPayload> getRoster() const; -			std::vector<boost::shared_ptr<Presence> > getAllPresence() const; - -			boost::signal<void (boost::shared_ptr<RosterPayload>)> onRosterChanged; -			boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChanged; - -			bool hasItem(const JID&) const; -			String getHostname(const JID&) const; -			int getPort(const JID&) const; - -		private: -			RosterItemPayload getRosterItem(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const; -			String getRosterName(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const; -			JID getJIDForService(const DNSSDService::Service& service) const; -			boost::shared_ptr<Presence> getPresence(const DNSSDService::Service& service, const DNSSDService::ResolveResult& info) const; - -			void handleStopped(bool); -			void handleServiceRegistered(const DNSSDService::Service& service); -			void handleServiceAdded(const DNSSDService::Service&); -			void handleServiceRemoved(const DNSSDService::Service&); -			void handleServiceResolved(const DNSSDService::Service& service, const DNSSDService::ResolveResult& result); - -		private: -			boost::shared_ptr<DNSSDService> dnsSDService; -			boost::optional<DNSSDService::Service> selfService; -			typedef std::map<DNSSDService::Service, DNSSDService::ResolveResult> ServiceMap; -			ServiceMap services; -	}; -} diff --git a/Swiften/LinkLocal/LinkLocalService.cpp b/Swiften/LinkLocal/LinkLocalService.cpp new file mode 100644 index 0000000..f567a63 --- /dev/null +++ b/Swiften/LinkLocal/LinkLocalService.cpp @@ -0,0 +1,23 @@ +#include "Swiften/LinkLocal/LinkLocalService.h" + +namespace Swift { + +String LinkLocalService::getDescription() const { +	LinkLocalServiceInfo info = getInfo(); +	if (!info.getNick().isEmpty()) { +		return info.getNick(); +	} +	else if (!info.getFirstName().isEmpty()) { +		String result = info.getFirstName(); +		if (!info.getLastName().isEmpty()) { +			result += " " + info.getLastName(); +		} +		return result; +	} +	else if (!info.getLastName().isEmpty()) { +		return info.getLastName(); +	} +	return getName(); +} + +} diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h new file mode 100644 index 0000000..f7e9e3c --- /dev/null +++ b/Swiften/LinkLocal/LinkLocalService.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" + +namespace Swift { +	class LinkLocalService { +		public: +			LinkLocalService( +					const DNSSDServiceID& id, +					const DNSSDResolveServiceQuery::Result& info) : +						id(id), +						info(info) {} + +			const DNSSDServiceID& getID() const { +				return id; +			} + +			const String& getName() const { +				return id.getName(); +			} + +			int getPort() const { +				return info.port; +			} + +			const String& getHostname() const { +				return info.host; +			} + +			LinkLocalServiceInfo getInfo() const { +				return LinkLocalServiceInfo::createFromTXTRecord(info.info); +			} + +			String getDescription() const; + +		private: +			DNSSDServiceID id; +			DNSSDResolveServiceQuery::Result info; +	}; +} diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp new file mode 100644 index 0000000..061bf2c --- /dev/null +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp @@ -0,0 +1,147 @@ +#include <boost/bind.hpp> +#include <iostream> + +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" +#include "Swiften/Network/HostAddress.h" + +namespace Swift { + +LinkLocalServiceBrowser::LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier) : querier(querier), haveError(false) { +} + +LinkLocalServiceBrowser::~LinkLocalServiceBrowser() { +	if (isRunning()) { +		std::cerr << "WARNING: LinkLocalServiceBrowser still running on destruction" << std::endl; +	} +} + + +void LinkLocalServiceBrowser::start() { +	assert(!isRunning()); +	haveError = false; +	browseQuery = querier->createBrowseQuery(); +	browseQuery->onServiceAdded.connect( +			boost::bind(&LinkLocalServiceBrowser::handleServiceAdded, this, _1)); +	browseQuery->onServiceRemoved.connect( +			boost::bind(&LinkLocalServiceBrowser::handleServiceRemoved, this, _1)); +	browseQuery->onError.connect( +			boost::bind(&LinkLocalServiceBrowser::handleBrowseError, this)); +	browseQuery->startBrowsing(); +} + +void LinkLocalServiceBrowser::stop() { +	assert(isRunning()); +	if (isRegistered()) { +		unregisterService(); +	} +	for (ResolveQueryMap::const_iterator i = resolveQueries.begin(); i != resolveQueries.end(); ++i) { +		i->second->stop(); +	} +	resolveQueries.clear(); +	services.clear(); +	browseQuery->stopBrowsing(); +	browseQuery.reset(); +	onStopped(haveError); +} + +bool LinkLocalServiceBrowser::isRunning() const { +	return browseQuery; +} + +bool LinkLocalServiceBrowser::hasError() const { +	return haveError; +} + +bool LinkLocalServiceBrowser::isRegistered() const { +	return registerQuery; +} + +void LinkLocalServiceBrowser::registerService(const String& name, int port, const LinkLocalServiceInfo& info) { +	assert(!registerQuery); +	registerQuery = querier->createRegisterQuery(name, port, info.toTXTRecord()); +	registerQuery->onRegisterFinished.connect( +		boost::bind(&LinkLocalServiceBrowser::handleRegisterFinished, this, _1)); +	registerQuery->registerService(); +} + +void LinkLocalServiceBrowser::updateService(const LinkLocalServiceInfo& info) { +	assert(registerQuery); +	registerQuery->updateServiceInfo(info.toTXTRecord()); +} + +void LinkLocalServiceBrowser::unregisterService() { +	assert(registerQuery); +	registerQuery->unregisterService(); +	registerQuery.reset(); +	selfService.reset(); +} + +std::vector<LinkLocalService> LinkLocalServiceBrowser::getServices() const { +	std::vector<LinkLocalService> result; +	for (ServiceMap::const_iterator i = services.begin(); i != services.end(); ++i) { +		result.push_back(LinkLocalService(i->first, i->second)); +	} +	return result; +} + +void LinkLocalServiceBrowser::handleServiceAdded(const DNSSDServiceID& service) { +	if (selfService && service == *selfService) { +		return; +	} +	boost::shared_ptr<DNSSDResolveServiceQuery> resolveQuery = querier->createResolveServiceQuery(service); +	resolveQuery->onServiceResolved.connect( +		boost::bind(&LinkLocalServiceBrowser::handleServiceResolved, this, service, _1)); +	std::pair<ResolveQueryMap::iterator, bool> r = resolveQueries.insert(std::make_pair(service, resolveQuery)); +	if (!r.second) { +		r.first->second = resolveQuery; +	} +	resolveQuery->start(); +} + +void LinkLocalServiceBrowser::handleServiceRemoved(const DNSSDServiceID& service) { +	ResolveQueryMap::iterator i = resolveQueries.find(service); +	if (i == resolveQueries.end()) { +		// Can happen after an unregister(), when getting the old 'self'  +		// service remove notification. +		return; +	} +	i->second->stop(); +	resolveQueries.erase(i); +	ServiceMap::iterator j = services.find(service); +	assert(j != services.end()); +	LinkLocalService linkLocalService(j->first, j->second); +	services.erase(j); +	onServiceRemoved(linkLocalService); +} + +void LinkLocalServiceBrowser::handleServiceResolved(const DNSSDServiceID& service, const boost::optional<DNSSDResolveServiceQuery::Result>& result) { +	if (result) { +		std::pair<ServiceMap::iterator, bool> r = services.insert(std::make_pair(service, *result)); +		if (r.second) { +			onServiceAdded(LinkLocalService(r.first->first, r.first->second)); +		} +		else { +			r.first->second = *result; +			onServiceChanged(LinkLocalService(r.first->first, r.first->second)); +		} +	} +} + +void LinkLocalServiceBrowser::handleRegisterFinished(const boost::optional<DNSSDServiceID>& result) { +	if (result) { +		selfService = result; +		onServiceRegistered(*result); +	} +	else { +		haveError = true; +		stop(); +	} +} + +void LinkLocalServiceBrowser::handleBrowseError() { +	haveError = true; +	stop(); +} + +} diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h new file mode 100644 index 0000000..7ef661c --- /dev/null +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h @@ -0,0 +1,63 @@ +#pragma once + +#include <boost/signal.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> +#include <map> +#include <vector> + +#include "Swiften/Base/String.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include "Swiften/LinkLocal/LinkLocalService.h" +#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" + +namespace Swift { +	class LinkLocalServiceBrowser { +		public: +			LinkLocalServiceBrowser(boost::shared_ptr<DNSSDQuerier> querier); +			~LinkLocalServiceBrowser(); + +			void start(); +			void stop(); +			bool isRunning() const; +			bool hasError() const; + +			void registerService( +					const String& name,  +					int port,  +					const LinkLocalServiceInfo& info = LinkLocalServiceInfo()); +			void updateService( +					const LinkLocalServiceInfo& info = LinkLocalServiceInfo()); +			void unregisterService(); +			bool isRegistered() const; + +			std::vector<LinkLocalService> getServices() const; + +			boost::signal<void (const LinkLocalService&)> onServiceAdded; +			boost::signal<void (const LinkLocalService&)> onServiceChanged; +			boost::signal<void (const LinkLocalService&)> onServiceRemoved; +			boost::signal<void (const DNSSDServiceID&)> onServiceRegistered; +			boost::signal<void (bool)> onStopped; + +		private: +			void handleServiceAdded(const DNSSDServiceID&); +			void handleServiceRemoved(const DNSSDServiceID&); +			void handleServiceResolved(const DNSSDServiceID& service, const boost::optional<DNSSDResolveServiceQuery::Result>& result); +			void handleRegisterFinished(const boost::optional<DNSSDServiceID>&); +			void handleBrowseError(); + +		private: +			boost::shared_ptr<DNSSDQuerier> querier; +			boost::optional<DNSSDServiceID> selfService; +			boost::shared_ptr<DNSSDBrowseQuery> browseQuery; +			boost::shared_ptr<DNSSDRegisterQuery> registerQuery; +			typedef std::map<DNSSDServiceID, boost::shared_ptr<DNSSDResolveServiceQuery> > ResolveQueryMap; +			ResolveQueryMap resolveQueries; +			typedef std::map<DNSSDServiceID, DNSSDResolveServiceQuery::Result> ServiceMap; +			ServiceMap services; +			bool haveError; +	}; +} diff --git a/Swiften/LinkLocal/Makefile.inc b/Swiften/LinkLocal/Makefile.inc index 788c000..715d686 100644 --- a/Swiften/LinkLocal/Makefile.inc +++ b/Swiften/LinkLocal/Makefile.inc @@ -1,18 +1,10 @@  SWIFTEN_SOURCES += \ -	Swiften/LinkLocal/DNSSDService.cpp \ -	Swiften/LinkLocal/LinkLocalRoster.cpp \ +	Swiften/LinkLocal/LinkLocalServiceBrowser.cpp \ +	Swiften/LinkLocal/LinkLocalService.cpp \  	Swiften/LinkLocal/LinkLocalServiceInfo.cpp \  	Swiften/LinkLocal/IncomingLinkLocalSession.cpp \  	Swiften/LinkLocal/OutgoingLinkLocalSession.cpp \  	Swiften/LinkLocal/LinkLocalConnector.cpp -ifeq ($(MACOSX),1) -SWIFTEN_SOURCES += \ -	Swiften/LinkLocal/AppleDNSSDService.cpp -endif -ifeq ($(HAVE_AVAHI),yes) -SWIFTEN_SOURCES += \ -	Swiften/LinkLocal/AvahiDNSSDService.cpp -endif - +include Swiften/LinkLocal/DNSSD/Makefile.inc  include Swiften/LinkLocal/UnitTest/Makefile.inc diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp new file mode 100644 index 0000000..9f91269 --- /dev/null +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp @@ -0,0 +1,379 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/bind.hpp> +#include <map> + +#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" +#include "Swiften/LinkLocal/LinkLocalService.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" +#include "Swiften/EventLoop/DummyEventLoop.h" + +using namespace Swift; + +class LinkLocalServiceBrowserTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(LinkLocalServiceBrowserTest); +		CPPUNIT_TEST(testConstructor); +		CPPUNIT_TEST(testStart); +		CPPUNIT_TEST(testServiceAdded); +		CPPUNIT_TEST(testServiceAdded_NoServiceInfo); +		CPPUNIT_TEST(testServiceAdded_RegisteredService); +		CPPUNIT_TEST(testServiceAdded_UnregisteredService); +		CPPUNIT_TEST(testServiceChanged); +		CPPUNIT_TEST(testServiceRemoved); +		CPPUNIT_TEST(testServiceRemoved_UnregisteredService); +		CPPUNIT_TEST(testError_BrowseErrorAfterStart); +		CPPUNIT_TEST(testError_BrowseErrorAfterResolve); +		CPPUNIT_TEST(testRegisterService); +		CPPUNIT_TEST(testRegisterService_Error); +		CPPUNIT_TEST(testRegisterService_Reregister); +		CPPUNIT_TEST(testUpdateService); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		LinkLocalServiceBrowserTest() {} + +		void setUp() { +			eventLoop = new DummyEventLoop(); +			querier = boost::shared_ptr<FakeDNSSDQuerier>(new FakeDNSSDQuerier("wonderland.lit")); +			aliceServiceID = new DNSSDServiceID("alice", "wonderland.lit"); +			aliceServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.wonderland.lit", "xmpp.wonderland.lit", 1234, LinkLocalServiceInfo().toTXTRecord()); +			testServiceID = new DNSSDServiceID("foo", "bar.local"); +			testServiceInfo = new DNSSDResolveServiceQuery::Result("_presence._tcp.bar.local", "xmpp.bar.local", 1234, LinkLocalServiceInfo().toTXTRecord()); +			testServiceInfo2 = new DNSSDResolveServiceQuery::Result("_presence.tcp.bar.local", "xmpp.foo.local", 2345, LinkLocalServiceInfo().toTXTRecord()); +			errorStopReceived = false; +			normalStopReceived = false; +		} + +		void tearDown() { +			addedServices.clear(); +			removedServices.clear(); +			changedServices.clear(); + +			delete aliceServiceID; +			delete aliceServiceInfo; +			delete testServiceInfo2; +			delete testServiceInfo; +			delete testServiceID; +			delete eventLoop; +		} + +		void testConstructor() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); + +			CPPUNIT_ASSERT(!testling->isRunning()); +			CPPUNIT_ASSERT(!testling->hasError()); +		} + +		void testStart() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); + +			CPPUNIT_ASSERT(testling->isRunning()); +			CPPUNIT_ASSERT(!testling->hasError()); + +			testling->stop(); +		} + +		void testServiceAdded() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); + +			querier->setServiceInfo(*testServiceID,*testServiceInfo); +			querier->addService(*testServiceID); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size())); +			CPPUNIT_ASSERT(addedServices[0].getID() == *testServiceID); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size())); +			std::vector<LinkLocalService> services = testling->getServices(); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size())); +			CPPUNIT_ASSERT(*testServiceID == services[0].getID()); +			CPPUNIT_ASSERT(testServiceInfo->port == services[0].getPort()); +			CPPUNIT_ASSERT(testServiceInfo->host == services[0].getHostname()); + +			testling->stop(); +		} + +		void testServiceAdded_NoServiceInfo() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); + +			querier->addService(*testServiceID); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(addedServices.size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size())); + +			testling->stop(); +		} + +		void testServiceAdded_RegisteredService() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); + +			testling->registerService("alice", 1234, LinkLocalServiceInfo()); +			eventLoop->processEvents(); +			querier->setServiceInfo(*aliceServiceID, *aliceServiceInfo); +			querier->addService(*aliceServiceID); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(addedServices.size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size())); + +			testling->stop(); +		} + +		void testServiceAdded_UnregisteredService() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); +			testling->registerService("alice", 1234, LinkLocalServiceInfo()); +			eventLoop->processEvents(); +			testling->unregisterService(); +			eventLoop->processEvents(); + +			querier->setServiceInfo(*aliceServiceID, *aliceServiceInfo); +			querier->addService(*aliceServiceID); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size())); +			CPPUNIT_ASSERT(addedServices[0].getID() == *aliceServiceID); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size())); +			std::vector<LinkLocalService> services = testling->getServices(); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size())); +			CPPUNIT_ASSERT(*aliceServiceID == services[0].getID()); +			CPPUNIT_ASSERT(aliceServiceInfo->port == services[0].getPort()); +			CPPUNIT_ASSERT(aliceServiceInfo->host == services[0].getHostname()); + +			testling->stop(); +		} + +		void testServiceRemoved_UnregisteredService() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); +			testling->registerService("alice", 1234, LinkLocalServiceInfo()); +			eventLoop->processEvents(); +			testling->unregisterService(); +			eventLoop->processEvents(); + +			querier->removeService(*aliceServiceID); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size())); + +			testling->stop(); +		} + +		void testServiceChanged() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			querier->setServiceInfo(*testServiceID,*testServiceInfo); +			querier->addService(*testServiceID); +			eventLoop->processEvents(); + +			querier->setServiceInfo(*testServiceID,*testServiceInfo2); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(changedServices.size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(removedServices.size())); +			CPPUNIT_ASSERT(changedServices[0].getID() == *testServiceID); +			std::vector<LinkLocalService> services = testling->getServices(); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(services.size())); +			CPPUNIT_ASSERT(*testServiceID == services[0].getID()); +			CPPUNIT_ASSERT(testServiceInfo2->port == services[0].getPort()); +			CPPUNIT_ASSERT(testServiceInfo2->host == services[0].getHostname()); + +			testling->stop(); +		} + +		void testServiceRemoved() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			querier->setServiceInfo(*testServiceID,*testServiceInfo); +			querier->addService(*testServiceID); +			eventLoop->processEvents(); + +			querier->removeService(*testServiceID); +			eventLoop->processEvents(); +			querier->setServiceInfo(*testServiceID,*testServiceInfo2); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(addedServices.size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(removedServices.size())); +			CPPUNIT_ASSERT(removedServices[0].getID() == *testServiceID); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size())); + +			testling->stop(); +		} + +		void testError_BrowseErrorAfterStart() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); + +			querier->setBrowseError(); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(!testling->isRunning()); +			CPPUNIT_ASSERT(testling->hasError()); +			CPPUNIT_ASSERT(errorStopReceived); +		} + +		void testError_BrowseErrorAfterResolve() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			querier->setServiceInfo(*testServiceID,*testServiceInfo); +			querier->addService(*testServiceID); +			eventLoop->processEvents(); + +			querier->setBrowseError(); +			eventLoop->processEvents(); +			querier->setServiceInfo(*testServiceID,*testServiceInfo2); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(!testling->isRunning()); +			CPPUNIT_ASSERT(testling->hasError()); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(testling->getServices().size())); +			CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changedServices.size())); +			CPPUNIT_ASSERT(errorStopReceived); +		} + +		void testRegisterService() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); + +			LinkLocalServiceInfo info; +			info.setFirstName("Foo"); +			testling->registerService("foo@bar", 1234, info); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord())); +			CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(registeredServices.size())); +			CPPUNIT_ASSERT(registeredServices[0] == DNSSDServiceID("foo@bar", "wonderland.lit")); +			testling->stop(); +		} + +		void testRegisterService_Error() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			LinkLocalServiceInfo info; +			testling->registerService("foo@bar", 1234, info); +			eventLoop->processEvents(); + +			querier->setRegisterError(); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(!testling->isRunning()); +			CPPUNIT_ASSERT(testling->hasError()); +			CPPUNIT_ASSERT(errorStopReceived); +			CPPUNIT_ASSERT(!querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord())); +		} + +		void testRegisterService_Reregister() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); +			LinkLocalServiceInfo info; +			info.setFirstName("Foo"); +			testling->registerService("foo@bar", 1234, info); +			eventLoop->processEvents(); +			testling->unregisterService(); +			eventLoop->processEvents(); + +			info.setFirstName("Bar"); +			testling->registerService("bar@baz", 3456, info); +			eventLoop->processEvents(); + +			CPPUNIT_ASSERT(querier->isServiceRegistered("bar@baz", 3456, info.toTXTRecord())); + +			testling->stop(); +		} + +		void testUpdateService() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling = createTestling(); +			testling->start(); +			eventLoop->processEvents(); + +			LinkLocalServiceInfo info; +			info.setFirstName("Foo"); +			testling->registerService("foo@bar", 1234, info); +			eventLoop->processEvents(); +			info.setFirstName("Bar"); +			testling->updateService(info); + +			CPPUNIT_ASSERT(querier->isServiceRegistered("foo@bar", 1234, info.toTXTRecord())); + +			testling->stop(); +		} + +	private: +		boost::shared_ptr<LinkLocalServiceBrowser> createTestling() { +			boost::shared_ptr<LinkLocalServiceBrowser> testling( +					new LinkLocalServiceBrowser(querier)); +			testling->onServiceAdded.connect(boost::bind( +					&LinkLocalServiceBrowserTest::handleServiceAdded, this, _1)); +			testling->onServiceChanged.connect(boost::bind( +					&LinkLocalServiceBrowserTest::handleServiceChanged, this, _1)); +			testling->onServiceRemoved.connect(boost::bind( +					&LinkLocalServiceBrowserTest::handleServiceRemoved, this, _1)); +			testling->onServiceRegistered.connect(boost::bind( +					&LinkLocalServiceBrowserTest::handleServiceRegistered, this, _1)); +			testling->onStopped.connect(boost::bind( +					&LinkLocalServiceBrowserTest::handleStopped, this, _1)); +			return testling; +		} + +		void handleServiceAdded(const LinkLocalService& service) { +			addedServices.push_back(service); +		} + +		void handleServiceRemoved(const LinkLocalService& service) { +			removedServices.push_back(service); +		} + +		void handleServiceChanged(const LinkLocalService& service) { +			changedServices.push_back(service); +		} + +		void handleServiceRegistered(const DNSSDServiceID& service) { +			registeredServices.push_back(service); +		} + +		void handleStopped(bool error) { +			CPPUNIT_ASSERT(!errorStopReceived); +			CPPUNIT_ASSERT(!normalStopReceived); +			if (error) { +				errorStopReceived = true; +			} +			else { +				normalStopReceived = true; +			} +		} + +	private: +		DummyEventLoop* eventLoop; +		boost::shared_ptr<FakeDNSSDQuerier> querier; +		std::vector<LinkLocalService> addedServices; +		std::vector<LinkLocalService> changedServices; +		std::vector<LinkLocalService> removedServices; +		std::vector<DNSSDServiceID> registeredServices; +		DNSSDServiceID* aliceServiceID; +		DNSSDResolveServiceQuery::Result* aliceServiceInfo; +		DNSSDServiceID* testServiceID; +		DNSSDResolveServiceQuery::Result* testServiceInfo; +		DNSSDResolveServiceQuery::Result* testServiceInfo2; +		bool errorStopReceived; +		bool normalStopReceived; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceBrowserTest); diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp index b850f14..b5d7ef5 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp @@ -10,11 +10,10 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture {  		CPPUNIT_TEST(testGetTXTRecord);  		CPPUNIT_TEST(testCreateFromTXTRecord);  		CPPUNIT_TEST(testCreateFromTXTRecord_InvalidSize); +		CPPUNIT_TEST(testGetTXTRecordCreateFromTXTRecord_RoundTrip);  		CPPUNIT_TEST_SUITE_END();  	public: -		LinkLocalServiceInfoTest() {} -  		void testGetTXTRecord() {  			LinkLocalServiceInfo info;  			info.setFirstName("Remko"); @@ -37,6 +36,28 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture {  			CPPUNIT_ASSERT_EQUAL(String("a"), info.getLastName());  		} + +		void testGetTXTRecordCreateFromTXTRecord_RoundTrip() { +			LinkLocalServiceInfo info; +			info.setFirstName("Remko"); +			info.setLastName("Tron\xc3\xe7on"); +			info.setEMail("remko-email@swift.im"); +			info.setJID(JID("remko-jid@swift.im")); +			info.setMessage("I'm busy"); +			info.setNick("el-tramo"); +			info.setStatus(LinkLocalServiceInfo::DND); +			info.setPort(1234); + +			LinkLocalServiceInfo info2 = LinkLocalServiceInfo::createFromTXTRecord(info.toTXTRecord()); +			CPPUNIT_ASSERT_EQUAL(info.getFirstName(), info2.getFirstName()); +			CPPUNIT_ASSERT_EQUAL(info.getLastName(), info2.getLastName()); +			CPPUNIT_ASSERT_EQUAL(info.getEMail(), info2.getEMail()); +			CPPUNIT_ASSERT_EQUAL(info.getJID(), info2.getJID()); +			CPPUNIT_ASSERT_EQUAL(info.getMessage(), info2.getMessage()); +			CPPUNIT_ASSERT_EQUAL(info.getNick(), info2.getNick()); +			CPPUNIT_ASSERT(info.getStatus() == info2.getStatus()); +			CPPUNIT_ASSERT(info.getPort() == info2.getPort()); +		}  };  CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceInfoTest); diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp new file mode 100644 index 0000000..69ec718 --- /dev/null +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp @@ -0,0 +1,62 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/LinkLocal/LinkLocalService.h" + +using namespace Swift; + +class LinkLocalServiceTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(LinkLocalServiceTest); +		CPPUNIT_TEST(testGetDescription_WithNick); +		CPPUNIT_TEST(testGetDescription_WithFirstName); +		CPPUNIT_TEST(testGetDescription_WithLastName); +		CPPUNIT_TEST(testGetDescription_WithFirstAndLastName); +		CPPUNIT_TEST(testGetDescription_NoInfo); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		void testGetDescription_WithNick() { +			LinkLocalService testling = createService("alice@wonderland", "Alice", "Alice In", "Wonderland"); + +			CPPUNIT_ASSERT_EQUAL(String("Alice"), testling.getDescription()); +		} + +		void testGetDescription_WithFirstName() { +			LinkLocalService testling = createService("alice@wonderland", "", "Alice In"); + +			CPPUNIT_ASSERT_EQUAL(String("Alice In"), testling.getDescription()); +		} + +		void testGetDescription_WithLastName() { +			LinkLocalService testling = createService("alice@wonderland", "", "", "Wonderland"); + +			CPPUNIT_ASSERT_EQUAL(String("Wonderland"), testling.getDescription()); +		} + +		void testGetDescription_WithFirstAndLastName() { +			LinkLocalService testling = createService("alice@wonderland", "", "Alice In", "Wonderland"); + +			CPPUNIT_ASSERT_EQUAL(String("Alice In Wonderland"), testling.getDescription()); +		} + +		void testGetDescription_NoInfo() { +			LinkLocalService testling = createService("alice@wonderland"); + +			CPPUNIT_ASSERT_EQUAL(String("alice@wonderland"), testling.getDescription()); +		} +	 +	private: +		LinkLocalService createService(const String& name, const String& nickName = String(), const String& firstName = String(), const String& lastName = String()) { +			DNSSDServiceID service(name, "local."); +			LinkLocalServiceInfo info; +			info.setFirstName(firstName); +			info.setLastName(lastName); +			info.setNick(nickName); +			return LinkLocalService(service,  +					DNSSDResolveServiceQuery::Result( +						name + "._presence._tcp.local", "rabbithole.local", 1234,  +						info.toTXTRecord())); +		} +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LinkLocalServiceTest); diff --git a/Swiften/LinkLocal/UnitTest/Makefile.inc b/Swiften/LinkLocal/UnitTest/Makefile.inc index abc1180..e5f1bf0 100644 --- a/Swiften/LinkLocal/UnitTest/Makefile.inc +++ b/Swiften/LinkLocal/UnitTest/Makefile.inc @@ -1,2 +1,4 @@  UNITTEST_SOURCES += \ +	Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp \ +	Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp \  	Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp diff --git a/Swiften/Makefile.inc b/Swiften/Makefile.inc index 57ff329..d7c3340 100644 --- a/Swiften/Makefile.inc +++ b/Swiften/Makefile.inc @@ -41,7 +41,6 @@ SWIFTEN_HEADERS += \  TARGETS += $(SWIFTEN_TARGET)  INSTALL_TARGETS += install-swiften  UNITTEST_LIBS += $(SWIFTEN_TARGET) -CLEANFILES += $(SWIFTEN_TARGET) $(SWIFTEN_OBJECTS)  DEPS += \  	$(SWIFTEN_SOURCES:.cpp=.dep)   //TODO: Add objective stuff diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index 6d23c93..6f7ff86 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -32,6 +32,10 @@ static void handleStartElement(void* client, const XML_Char* name, const XML_Cha  static void handleEndElement(void* client, const XML_Char* name) {  	std::pair<String,String> nsTagPair = String(name).getSplittedAtFirst(NAMESPACE_SEPARATOR); +	if (nsTagPair.second == "") { +		nsTagPair.second = nsTagPair.first; +		nsTagPair.first = ""; +	}  	static_cast<XMLParserClient*>(client)->handleEndElement(nsTagPair.second, nsTagPair.first);  } diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index a26b31b..6a42d0d 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -2,7 +2,7 @@  #include <cppunit/extensions/TestFactoryRegistry.h>  #include <vector> -#ifdef HAVE_CONFIG_H +#ifdef HAVE_SWIFTEN_CONFIG_H  #include "Swiften/config.h"  #endif  #include "Swiften/Base/String.h" @@ -17,10 +17,10 @@  using namespace Swift;  template <typename ParserType> -class XMLParserTest : public CppUnit::TestFixture -{ +class XMLParserTest : public CppUnit::TestFixture {  		CPPUNIT_TEST_SUITE(XMLParserTest);  		CPPUNIT_TEST(testParse_NestedElements); +		CPPUNIT_TEST(testParse_ElementInNamespacedElement);  		CPPUNIT_TEST(testParse_CharacterData);  		CPPUNIT_TEST(testParse_NamespacePrefix);  		CPPUNIT_TEST(testParse_UnhandledXML); @@ -30,8 +30,6 @@ class XMLParserTest : public CppUnit::TestFixture  		CPPUNIT_TEST_SUITE_END();  	public: -		XMLParserTest() {} -  		void testParse_NestedElements() {  			ParserType testling(&client_); @@ -46,17 +44,51 @@ class XMLParserTest : public CppUnit::TestFixture  			CPPUNIT_ASSERT_EQUAL(String("iq"), client_.events[0].data);  			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.size());  			CPPUNIT_ASSERT_EQUAL(String("get"), client_.events[0].attributes["type"]); +			CPPUNIT_ASSERT_EQUAL(String(), client_.events[0].ns);  			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type);  			CPPUNIT_ASSERT_EQUAL(String("query"), client_.events[1].data); -			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].attributes.size()); -			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[1].attributes["xmlns"]); +			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.size()); +			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[1].ns);  			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type);  			CPPUNIT_ASSERT_EQUAL(String("query"), client_.events[2].data); +			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[2].ns);  			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type);  			CPPUNIT_ASSERT_EQUAL(String("iq"), client_.events[3].data); +			CPPUNIT_ASSERT_EQUAL(String(), client_.events[3].ns); +		} + +		void testParse_ElementInNamespacedElement() { +			ParserType testling(&client_); + +			CPPUNIT_ASSERT(testling.parse( +				"<query xmlns='jabber:iq:version'>" +          "<name>Swift</name>" +				"</query>")); + +			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), client_.events.size()); + +			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); +			CPPUNIT_ASSERT_EQUAL(String("query"), client_.events[0].data); +			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.size()); +			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[0].ns); + +			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); +			CPPUNIT_ASSERT_EQUAL(String("name"), client_.events[1].data); +			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[1].ns); + +			CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); +			CPPUNIT_ASSERT_EQUAL(String("Swift"), client_.events[2].data); + +			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); +			CPPUNIT_ASSERT_EQUAL(String("name"), client_.events[3].data); +			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[3].ns); + +			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[4].type); +			CPPUNIT_ASSERT_EQUAL(String("query"), client_.events[4].data); +			CPPUNIT_ASSERT_EQUAL(String("jabber:iq:version"), client_.events[4].ns);  		}  		void testParse_CharacterData() { @@ -96,16 +128,20 @@ class XMLParserTest : public CppUnit::TestFixture  			CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size());  			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); -			CPPUNIT_ASSERT_EQUAL(String("p:x"), client_.events[0].data); +			CPPUNIT_ASSERT_EQUAL(String("x"), client_.events[0].data); +			CPPUNIT_ASSERT_EQUAL(String("bla"), client_.events[0].ns);  			CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); -			CPPUNIT_ASSERT_EQUAL(String("p:y"), client_.events[1].data); +			CPPUNIT_ASSERT_EQUAL(String("y"), client_.events[1].data); +			CPPUNIT_ASSERT_EQUAL(String("bla"), client_.events[1].ns);  			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); -			CPPUNIT_ASSERT_EQUAL(String("p:y"), client_.events[2].data); +			CPPUNIT_ASSERT_EQUAL(String("y"), client_.events[2].data); +			CPPUNIT_ASSERT_EQUAL(String("bla"), client_.events[2].ns);  			CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); -			CPPUNIT_ASSERT_EQUAL(String("p:x"), client_.events[3].data); +			CPPUNIT_ASSERT_EQUAL(String("x"), client_.events[3].data); +			CPPUNIT_ASSERT_EQUAL(String("bla"), client_.events[3].ns);  		}  		void testParse_UnhandledXML() { @@ -158,24 +194,26 @@ class XMLParserTest : public CppUnit::TestFixture  					Event(  							Type type,   							const String& data,  +              const String& ns,  							const AttributeMap& attributes) -								: type(type), data(data), attributes(attributes) {} -					Event(Type type, const String& data) -								: type(type), data(data) {} +								: type(type), data(data), ns(ns), attributes(attributes) {} +					Event(Type type, const String& data, const String& ns = String()) +								: type(type), data(data), ns(ns) {}  					Type type;  					String data; +          String ns;  					AttributeMap attributes;  				};  				Client() {} -				virtual void handleStartElement(const String& element, const AttributeMap& attributes) { -					events.push_back(Event(StartElement, element, attributes)); +				virtual void handleStartElement(const String& element, const String& ns, const AttributeMap& attributes) { +					events.push_back(Event(StartElement, element, ns, attributes));  				} -				virtual void handleEndElement(const String& element) { -					events.push_back(Event(EndElement, element)); +				virtual void handleEndElement(const String& element, const String& ns) { +					events.push_back(Event(EndElement, element, ns));  				}  				virtual void handleCharacterData(const String& data) { diff --git a/Swiften/QA/ClientTest/Makefile.inc b/Swiften/QA/ClientTest/Makefile.inc index 16a87cf..b9ab167 100644 --- a/Swiften/QA/ClientTest/Makefile.inc +++ b/Swiften/QA/ClientTest/Makefile.inc @@ -6,7 +6,7 @@ CLIENTTEST_OBJECTS = \  TEST_TARGETS += ClientTest -CLEANFILES += $(CLIENTTEST_OBJECTS) $(CLIENTTEST_TARGET) +CLEANFILES += $(CLIENTTEST_TARGET)  DEPS += $(CLIENTTEST_SOURCES:.cpp=.dep)  $(CLIENTTEST_TARGET): $(SWIFTEN_TARGET) $(CLIENTTEST_OBJECTS) $(BUNDLED_LIBS) diff --git a/Swiften/QA/NetworkTest/Makefile.inc b/Swiften/QA/NetworkTest/Makefile.inc index 5ac14c0..b263cdb 100644 --- a/Swiften/QA/NetworkTest/Makefile.inc +++ b/Swiften/QA/NetworkTest/Makefile.inc @@ -8,7 +8,7 @@ NETWORKTEST_OBJECTS = \  TEST_TARGETS += NetworkTest -CLEANFILES += $(NETWORKTEST_OBJECTS) $(NETWORKTEST_TARGET) +CLEANFILES += $(NETWORKTEST_TARGET)  DEPS += $(NETWORKTEST_SOURCES:.cpp=.dep)  $(NETWORKTEST_TARGET): $(SWIFTEN_TARGET) $(CPPUNIT_TARGET) $(NETWORKTEST_OBJECTS) $(BUNDLED_LIBS) diff --git a/Swiften/Session/Session.cpp b/Swiften/Session/Session.cpp index 5ee98e7..92d1fdc 100644 --- a/Swiften/Session/Session.cpp +++ b/Swiften/Session/Session.cpp @@ -14,6 +14,7 @@ Session::Session(  			connection(connection),  			payloadParserFactories(payloadParserFactories),  			payloadSerializers(payloadSerializers), +      streamStack(0),  			initialized(false) {  } diff --git a/configure.in b/configure.in index 9025855..80e69c0 100644 --- a/configure.in +++ b/configure.in @@ -13,6 +13,7 @@ AC_CANONICAL_HOST  AH_TEMPLATE(HAVE_OPENSSL, [OpenSSL library available])  AH_TEMPLATE(HAVE_LIBXML, [LibXML library available])  AH_TEMPLATE(HAVE_EXPAT, [Expat library available]) +AH_TEMPLATE(HAVE_BONJOUR, [Apple Bonjour SDK available])  AH_TEMPLATE(HAVE_AVAHI, [Avahi library available])  ################################################################################ @@ -194,13 +195,15 @@ fi  # Resolv  AC_CHECK_LIB(resolv, inet_aton) -# Avahi +# DNSSD Service  case $host in  	*-*-cygwin*)  		;;  	*-mingw32*)  		;;  	*-*-darwin*) +		HAVE_BONJOUR=yes +    AC_DEFINE(HAVE_BONJOUR)  		;;  	*)      AX_AVAHI() @@ -239,6 +242,7 @@ echo  AC_SUBST(SET_MAKE)  AC_SUBST(HAVE_EXPAT)  AC_SUBST(HAVE_AVAHI) +AC_SUBST(HAVE_BONJOUR)  AC_SUBST(CONFIG_CXX)  AC_SUBST(CONFIG_CXXFLAGS)  AC_SUBST(CONFIG_CC) diff --git a/tools/coverage/FilterLCovData.py b/tools/coverage/FilterLCovData.py index 8b8d24e..8d56a7f 100755 --- a/tools/coverage/FilterLCovData.py +++ b/tools/coverage/FilterLCovData.py @@ -1,9 +1,15 @@  #!/usr/bin/env python -import sys, re +# TODO: Add uncovered non-ignored files + +import sys, re, os.path  assert(len(sys.argv) == 2) +def isIgnored(file) : +  return (find.find("/Swiften/") == -1 and find.find("/Slimber/") == -1 and find.find("/Swift/") == -1) or (find.find("/UnitTest/") != -1 or find.find("/QA/") != -1) +   +  output = []  inputFile = open(sys.argv[1])  inIgnoredFile = False @@ -12,11 +18,12 @@ for line in inputFile.readlines() :      if line == "end_of_record\n" :        inIgnoredFile = False    else : -    if line.startswith("SF:") and (line.find("/Swiften/") == -1 or line.find("/UnitTest/") != -1 or line.find("/QA/") != -1 or line.find("/3rdParty/") != -1): +    if line.startswith("SF:") and isIgnored(line) :        inIgnoredFile = True      else : -      if line.startswith("SF:") : -        line = line.replace("/./Swiften/", "/Swiften/") +      m = re.match("SF:(.*)", line) +      if m : +        line = "SF:" + os.path.realpath(m.group(1)) + "\n"        output.append(line)  inputFile.close() diff --git a/tools/coverage/GenerateCoverageResults.sh b/tools/coverage/GenerateCoverageResults.sh index 75efaa9..f006e4b 100755 --- a/tools/coverage/GenerateCoverageResults.sh +++ b/tools/coverage/GenerateCoverageResults.sh @@ -31,6 +31,7 @@ $LCOVDIR/lcov --zerocounters --directory $SOURCE_DIR  # All tests  make -C $SOURCE_DIR test  $LCOVDIR/lcov --capture --directory $SOURCE_DIR -b $SOURCE_DIR --output-file $OUTPUT_DIR/all.info --test-name all +cp $OUTPUT_DIR/all.info $OUTPUT_DIR/all.info.orig  $SCRIPT_DIR/FilterLCovData.py $OUTPUT_DIR/all.info  # Generate HTML | 
 Swift
 Swift