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 |